Contents
Several ways to hand over beans to Spring container management
Spring core
Spring
The core is IOC and AOP .
The so-called IoC
, for spring
the framework, is responsible spring
for controlling the life cycle of objects and the relationship between objects.
As for a more detailed explanation, or to deeply understand Spring
these two cores, it is not the purpose of this article, so I will not go into detail yet.
In our Spring
project, we need to hand Bean
it over to Spring
the container, that is, IOC management, so that you can use annotations for dependency injection.
Package scanning + component annotation
For the case where the class is written by ourselves
This method is most commonly used in our daily development to add classes with , , , annotations spring
under the scan path to the container.@Component
@Controller
@Service
@Repository
spring IOC
If you have used MybatisPlus, this is the same as its package scanning injection.
Then our ComponentScan
annotation has three configurations.
Configuration item one
basePackages
Path used to define scanned packages.
@ComponentScan(basePackages = "com.timemail.bootmp")
For example, this is to scan com.timemail.bootmp
the entire package for classes with the above specified annotations and put them in IOC
.
I found a complete example in another article:
@Component public class Person { private String name; public String getName () { return name; } public void setName (String name) { this .name = name; } @Override public String toString () { return "Person{" + "name='" + name + '\'' + '}' ; } } @ComponentScan(basePackages = "com.springboot.initbean.*") public class Demo1 { public static void main (String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext (Demo1.class); Person bean = applicationContext.getBean(Person. class); System.out.println(bean); } }
//Result Person{name= 'null' }
This shows that Person
the class in the above code has been managed by the IOC container.
Configuration item two
includeFilters
include rules
Filter annotation uses FilterType.CUSTOM to customize scanning rules. You need to implement the TypeFilter interface to implement the match method. The parameter MetadataReader is the current class information (annotations, class path, class source information…) MetadataReaderFactory MetadataReader factory class.
Configuration item three
excludeFilters
Remove rule
Same inclusion rules.
I haven’t used these last two configuration items much, and I’m not very familiar with them, so please check the relevant information for detailed use.
@Configuration
+@Bean
@Configuration
+ @Bean
is also a commonly used way for us to put it into containers.
@Configuration
Used to declare configuration classes
@Bean
used to declare aBean
@Configuration public class Demo { @Bean public Person person () { Person person = new Person (); person.setAge( 10 ); return person; } }
like this.
Then we know that SSM
inside, usually we will configure it in xml bean
.
@Configuration public class ConfigBean { }
Then our @Configuration
annotation is equivalent to a Bean
configuration xml
.
<?xml version= "1.0" encoding= "UTF-8" ?> < beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org /2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd" > </beans>
Properties in Bean annotations
Our @Bean
annotations also have many properties that can be configured.
We can view its source code:
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) //@1 @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Bean { @AliasFor("name") String[] value() default {}; @AliasFor("value") String[] name() default {}; @Deprecated Autowire autowire () default Autowire.NO; boolean autowireCandidate () default true ; String initMethod () default "" ; String destroyMethod () default AbstractBeanDefinition.INFER_METHOD; }
- value and name are the same. When setting, you can only choose one of these two parameters. The reason is caused by @AliasFor
- value: string array, the first value is used as the name of the bean, and other values are used as aliases of the bean
- autowire: This parameter is marked @Deprecated, which means it has expired and is not recommended for use.
- autowireCandidate: Whether to serve as a candidate bean when injecting other objects.
- initMethod: bean initialization method. This is related to the life cycle and will be explained in detail later.
- destroyMethod: The method of bean destruction, which is also related to the life cycle and will be explained in detail later.
Expand
For @Configuration
a modified class, spring
the container will cglib
create a proxy for this class. The proxy will intercept all modified @Bean
methods bean
and ensure that these methods are only called once by default (single case) to ensure that these bean
are the same bean
, that is, singleton Example.
@Import annotation import
Let’s look at the source code first:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Import { /** * Used to import a class file * { @link Configuration @Configuration }, { @link ImportSelector}, * { @link ImportBeanDefinitionRegistrar}, or regular component classes to import. */ Class<?>[] value(); }
@Import
Can only be used for class annotations.
Here I will directly transfer the content of the public account: Xiaoha learns Java.
His explanation is very detailed.
The first two methods may be used more often and must be known in daily development. The @Import annotation may not be used particularly much, but it is also very important. It is often used when extending Spring. It is often used. Use it with custom annotations, and then import a configuration file into the container.
Regarding the @Import annotation, I will introduce a little more. It has four ways to use it. This is the source code of the @Import annotation, which means it can only be placed on a class.
@Import directly imports classes
public class Person { private String name; public String getName () { return name; } public void setName (String name) { this .name = name; } @Override public String toString () { return "Person{" + "name='" + name + '\'' + '}' ; } } /** * Directly use @Import to import the person class, then try to get it from the applicationContext, and get it successfully **/ @Import(Person.class) public class Demo1 { public static void main (String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext (Demo1.class); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); } }
The above code directly @Import
imports a class, and then it is automatically placed in IOC
the container.
Note: Our
Person
class does not need any annotations, just import it directly.
@Import + ImportSelector
In fact @Import
, it is very clear in the source code of the annotation. If you are interested, you can take a look. We implement an ImportSelector
interface, then implement the methods in it and import it.
@Import(MyImportSelector.class) public class Demo1 { public static void main (String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext (Demo1.class); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); } } class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String []{ "com.springboot.pojo.Person" }; } }
I customized a MyImportSelector
custom ImportSelector
interface, overridden selectImports
the method, and then wrote the fully qualified name of the class we want to import in it. It is also very simple to implement.
@Import + ImportBeanDefinitionRegistrar
This method also requires us to implement ImportBeanDefinitionRegistrar
the methods in the interface. The specific code is as follows:
@Import(MyImportBeanDefinitionRegistrar.class) public class Demo1 { public static void main (String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext (Demo1.class); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); } } class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions (AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // Build a beanDefinition. I will introduce beanDefinition later, which can be simply understood as the definition of bean. AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Person.class).getBeanDefinition(); // Register the beanDefinition into the Ioc container. registry.registerBeanDefinition( "person" , beanDefinition); } }
The above implementation is actually Import
similar to the second method. Both need to implement the interface and then import it. I came into contact with a new concept, BeanDefinition
which can be simply understood as bean
the definition ( bean
metadata) of , which also needs to be managed in an IOC container. The metadata bean
is created , applicationContext
and then bean
the metadata is created Bean
.
@Import + DeferredImportSelector
This method also requires us to implement the interface. In fact , it is @Import
similar to the second method. DeferredImportSelector
It is ImportSelector
a sub-interface of , so the implementation method is the same as the second method. It’s just Spring
that the processing method is different, it Spring Boot
is related to the delayed import of the automatic import configuration file, which is very important. How to use it:
@Import(MyDeferredImportSelector.class) public class Demo1 { public static void main (String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext (Demo1.class); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); } } class MyDeferredImportSelector implements DeferredImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // Also put Person's fully qualified name directly return new String []{Person.class.getName()}; } }
Regarding @Import
the use of annotations, there are probably the above three methods. Of course, it can also be used with @Configuration
annotations to import a configuration class.
FactoryBean interface
Speaking of which FactoryBean
, many of our entry-level developers can easily confuse him with BeanFactory
.
BeanFactory
It is the container root interface of all Spring Beans. It defines a set of specifications for Spring containers and provides a complete set of specifications for IOC containers, such as the commonly used getBean method.That is what we often call
Bean
a factory.
And ours FactoryBean
, it’s actually one Bean
, Factory
it’s his name, as the name suggests.
@Configuration public class Demo1 { @Bean public PersonFactoryBean personFactoryBean () { return new PersonFactoryBean (); } public static void main (String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext (Demo1.class); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); } } class PersonFactoryBean implements FactoryBean <Person> { @Override public Person getObject () throws Exception { return new Person (); } @Override public Class<?> getObjectType() { return Person.class; } }
Here, we can first look at FactoryBean
the method in:
It is an interface class.
Then we need to have a class to inherit this interface and override the method.
Bean
Here, we put the classes that need to be registered FactoryBean
into the generics.
getObject
Method is used to directly return the created object.
getObjectType
Return the class directly class
.
Then in fact, you still need to use @Bean
annotations to return the class object that inherits the interface.
Then Configuration
annotate and change this class springboot
to the configuration class, which is equivalent to the file springmvc
in xml
.
We can use AnnotationConfigApplicationContext
the getBean
method to see if it is IOC
managed.
After running, you can see that the object address is output.
It means success.
Using BeanDefinitionRegistryPostProcessor
When writing this article, I also checked the information of many big names on the Internet.
There is a method that I’m not familiar with.
then……
Start copying the original text….
In fact, this method is also used . It is a method that
BeanDefinitionRegistry
will be executed when the Spring container is started . It probably means that after the beanDefinition is loaded, the beanDefinition will be post-processed. You can adjust the beanDefinition in the IOC container here to interfere with the later. Initialize the bean.
BeanDefinitionRegistryPostProcessor
postProcessBeanDefinitionRegistry ()
public class Demo1 { public static void main (String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext (); MyBeanDefinitionRegistryPostProcessor beanDefinitionRegistryPostProcessor = new MyBeanDefinitionRegistryPostProcessor (); applicationContext.addBeanFactoryPostProcessor(beanDefinitionRegistryPostProcessor); applicationContext.refresh(); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); } } class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry (BeanDefinitionRegistry registry) throws BeansException { AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Person.class).getBeanDefinition(); registry.registerBeanDefinition( "person" , beanDefinition); } @Override public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException { } }
In the above code, we manually registered person in beanDefinitionRegistry BeanDefinition
, and finally successfully added person to applicationContext.