1. Spring registers beans

This article explains usage first, and the next article looks at how to register beans into an IOC container in the following scenario.

1.1. Use @bean annotations

This usage is very common in projects and is almost inevitable. Let’s see how it works:

@Configuration
public class TestConfig {

    @Bean
    public TestBean testBean(){
        return new TestBean();
    }
    public static class TestBean{}
}

Copy the code

The Bean is registered with the IOC container. The Bean name is the method name by default and case-insensitive, so if your method name is TestBean(), the Bean name is TestBean. Of course, we can also specify the Bean name by name or value, such as @bean (value = “testBean”). If both exist, an error will be reported.

Let’s look at the other attributes:

AutowireCandidate: The default is true. If set to false, getting beans by byType is an error, which can be obtained using the Resource annotation.

InitMethod: The initialization method called after the Bean is instantiated and the value is the name of the method in the Bean class.

DestroyMethod: A cleanup method called when the Bean is about to be destroyed, and its value is the method name in the Bean class.

Can @bean annotations only be defined under the @Configuration class? NO, NO, NO. It can be defined under any annotation that IOC can scan, such as the @Component annotation.

1.2. Annotate component scanning with @ComponentScan

Let’s start with common usage:

@ComponentScan(basePackages = "com.rookie.spring.source.run.component")
@Configuration
public class TestConfig {
}
Copy the code

Using @ComponentScan, it scans all classes under specified packages (including subpackages) and adds beans to the IOC container as long as they contain @Component, @Configuration, and other Spring declaration annotations.

Depth usage:

The ComponentScan annotation has two such properties: IncludeFilters and excludeFilters. The former contains only rules and the latter excludes including rules. Their values are in the form of an @filter annotation.

1, the ANNOTATION

The first is to include or not include in the form of annotations, such as:

@ComponentScan(basePackages = "com.rookie.spring.source.run.component",
        includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Configuration.class),
        useDefaultFilters = false)
Copy the code

UseDefaultFilters = false disables the default rule because the default rule is to scan all. Only the Configuration annotations are scanned.

2, ASSIGNABLE_TYPE

This one contains the type we are given, and both the given type and subclass will be included in the IOC container.

public class TestBean1 extends TestBean {
}
public class TestBean {
}

@ComponentScan(basePackages = "com.rookie.spring.source.run.component",
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Configuration.class),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = TestBean.class)},
        useDefaultFilters = false)
@Configuration
public class TestConfig {
}
Copy the code

Then we see that testBean is registered. Why would an annotation instance like @Component be registered in IOC without being tagged? Because ComponentScan scans all the files in a package, it registers beans into the IOC container as long as the filtering rules we define are met.

3, ASPECTJ

ASPECTJ uses ASPECTJ expressions

4, the REGEX

REGEX uses regular expressions

5, the CUSTOM

This is the way we use the SpringBootApplication annotation. Let me explain the rules: this way you can customize the scan rules, and it accepts a class that implements the TypeFilter interface.

Public class MyTypeFilter implements TypeFilter {/** ** @param metadataReader Information about the current class * @param metadataReaderFactory * @return Matching result * @throws IOException exception */ @Override public Boolean match(MetadataReader MetadataReader, MetadataReaderFactory MetadataReaderFactory) throws IOException {// Obtains the current scanned class information. ClassMetadata ClassMetadata = metadataReader.getClassMetadata(); return classMetadata.getClassName().contains("com.rookie.spring.source.run.component.TestBean"); } } @ComponentScan(basePackages = "com.rookie.spring.source.run.component", includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM,classes = MyTypeFilter.class)}, useDefaultFilters = false) @Configuration public class TestConfig { }Copy the code

When it scans the class, it scans the TestBean, and then meets my matching rules (which return true) and registers it.

1.3. Use @import annotations

In the following example, it is typical to look directly at the Spring source code implementation.

We point into @ EnableTransactionManagement annotations, discovered the @ Import (TransactionManagementConfigurationSelector. Class), its role is to Import, Classes are registered in the IOC container.

The annotation is placed somewhere that Spring can scan, otherwise Spring will not actively parse the annotation.

If we want to use annotations of words, we can do a similar to the function of EnableTransactionManagement plug type import configuration class, so that it can realize dynamic open some beans.

1.4. Implement ImportSelector interface

public interface ImportSelector { /** * Select and return the names of which class(es) should be imported based on * the  {@link AnnotationMetadata} of the importing @{@link Configuration} class. */ String[] selectImports(AnnotationMetadata importingClassMetadata); }Copy the code

We still see TransactionManagementConfigurationSelector this class, look at its inheritance relationships found it indirectly realized ImportSelector interface, basically see it this way:

@Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String[] {determineTransactionAspectClass()}; default: return null; }}Copy the code

The role of this method is based on your return fully qualified name of the class (org. Springframework. Context. The annotation. AutoProxyRegistrar) array to create Bean.

Classes that implement ImportSelector also need to be imported using @import.

1.5, realizing ImportBeanDefinitionRegistrar interface

public interface ImportBeanDefinitionRegistrar {

	/**
	 * Register bean definitions as necessary based on the given annotation metadata of
	 * the importing {@code @Configuration} class.
	 * <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
	 * registered here, due to lifecycle constraints related to {@code @Configuration}
	 * class processing.
	 * @param importingClassMetadata annotation metadata of the importing class
	 * @param registry current bean definition registry
	 */
	void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);

}
Copy the code

This we’ll look at @ MapperScan (org. Mybatis. Spring. The annotation) import MapperScannerRegistrar found it implements ImportBeanDefinitionRegistrar:

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        AnnotationAttributes mapperScanAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
        if (mapperScanAttrs != null) {
            this.registerBeanDefinitions(mapperScanAttrs, registry);
        }

    }
Copy the code

It takes the BeanDefinitionRegistry Bean definition information, and if you add BeanDefinition to it, it registers the corresponding object. It goes further than that, essentially resolving the annotation properties, and then scanning for the class registration Bean under the corresponding package. Let’s make our own simple one.

registry.registerBeanDefinition("testBean",new RootBeanDefinition(TestBean.class));
Copy the code

This registers a Bean whose Bean name is testBean and whose type is testBean.

What if you register a parameter constructor? Here’s how:

BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class);
        beanDefinitionBuilder.addConstructorArgValue(1);
        registry.registerBeanDefinition("testBean",beanDefinitionBuilder.getBeanDefinition());
Copy the code

AddConstructorArgValue adds according to the order of constructor arguments.

Realized ImportBeanDefinitionRegistrar class is also need to use @ Import Import.

1.6. Implement FactoryBean interface

public class MyFactoryBean implements FactoryBean<TestBean> { @Override public TestBean getObject() throws Exception { return new TestBean(); } @Override public Class<? > getObjectType() { return TestBean.class; } @Override public boolean isSingleton() { return true; } } @Import(MyFactoryBean.class) @Configuration public class TestConfig { }Copy the code

Then the TestBean is registered. When printing, we find that the Bean name is the fully qualified name of MyFactoryBean, but it is of type TestBean. If we want to get a Bean of type MyFactoryBean, This is obtained by the Bean name &myFactoryBean.

Use the Spring. factories configuration

In our Spring Boot project, it is common to just scan all classes under the main class and load some classes marked by specific annotations into the IOC container, but if we separate packages, how can we easily load classes from other packages? Spring Boot provides a java-like SPI (service discovery) mechanism called Spring. factories. You just need to create a meta-INF folder in the Resources directory, create a Spring. factories file, and configure it

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.jylcloud.jyl.common.commondcs.config.RedissonManagerConfig

Copy the code

The spring.factories file that imports the current package will be automatically scanned, parsed and loaded into the IOC container. The implementation code is in the SpringFactoriesLoader class of Spring-Core.

1.8. Use @Component, @Repository, @service, @Controller, @restController

I’m not going to talk about that.

2, summarize

I’m not going to summarize it, but watch it. There are other ways to register beans that are placed elsewhere.

The original address