Source download
The source code of this chapter is github
What is the lifecycle of spring beans
For ordinary Java objects, create the object when new, and then the object can be used. Once the object is no longer used, Java automatically garbage collects it.
The objects in Spring are beans. Beans are no different from ordinary Java objects, except that Spring no longer uses the new object itself, but the IoC container helps us instantiate the object and manage it. We can ask the IoC container which object we need. IoC actually solves the coupling problem between objects. The life cycle of Spring beans is completely controlled by the container.
Bean life cycle
The life cycle phases of spring beans are:
bean definition
bean registration
Materialization
Dependency injection
initialization
Destroy
- 1.bean definition: it is to load and read the meta information of the bean from the xml or annotation location resource and define it as a BeanDefinition object
- 2.bean registration: put the BeanDefinition object into the cache pool map according to the corresponding rules
- 3. Instantiation: instantiate the real bean according to the BeanDefinition, that is, call the constructor
- 4. Dependency injection: call setter method for attribute assignment, that is, dependency injection (DI)
- 5. Initialization: initialization is the stage where users can customize the extension
- 6. Destroy: destroy is a user-defined extension stage
Note: others are expansion points before and after this stage
View bean definition and registration from the perspective of Spring
refresh()
public void refresh() throws BeansException, IllegalStateException { synchronized(this.startupShutdownMonitor) { StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh"); // Prepare the environment information related to Bean initialization. An empty initPropertySources() method is provided internally to provide users with an opportunity to change the relevant environment information this.prepareRefresh(); // Create a BeanFactory instance and register the relevant bean information ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); // Register Aware and Processor instances, and register some Editor information required for subsequent processing of requests this.prepareBeanFactory(beanFactory); try { // An empty method is provided to supply subclasses to customize some information of the generated BeanFactory this.postProcessBeanFactory(beanFactory); StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); // Call relevant methods of beanfactoryprocessor and its sub interfaces. These interfaces provide an entry for the caller to modify the generated BeanDefinition this.invokeBeanFactoryPostProcessors(beanFactory); // Register BeanPostProcessor this.registerBeanPostProcessors(beanFactory); beanPostProcess.end(); // bean information required to initialize internationalization this.initMessageSource(); // Initializes the bean information of the event broadcaster this.initApplicationEventMulticaster(); // An empty method provided by. Subclasses are used to provide custom bean information or modify existing bean information this.onRefresh(); // Register event listener this.registerListeners(); // Instantiation of registered non deferred (profile specified) bean s this.finishBeanFactoryInitialization(beanFactory); // Clear the cached resource information, initialize some bean s related to the declaration cycle, and publish the event that the Context has been initialized this.finishRefresh(); } catch (BeansException var10) { if (this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10); } // If an exception occurs, the generated bean will be destroyed this.destroyBeans(); // Reset refresh field information this.cancelRefresh(var10); throw var10; } finally { // Initialize some cache information this.resetCommonCaches(); contextRefresh.end(); } } } Copy code
View bean definition and registration from the perspective of SpringBoot
1. Automatically load configuration class
2. bean definition and registration
Note: spring boot only has more automatic configuration related processes than spring, and a layer of logic encapsulation is made on spring.
Instantiation, dependency injection, initialization
AbstractAutowireCapableBeanFactory is an implementation class of the AutowireCapableBeanFactory interface, where AbstractAutowireCapableBeanFactory implements a method doCreateBean() of the class
//Location: AbstractAutowireCapableBeanFactory#doCreateBean protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { // Instantiation phase instanceWrapper = this.createBeanInstance(beanName, mbd, args); } ... Object exposedObject = bean; try { // Dependency injection, attribute assignment phase this.populateBean(beanName, mbd, instanceWrapper); // Initialization phase exposedObject = this.initializeBean(beanName, exposedObject, mbd); } catch (Throwable var18) { ... } ... } Copy code
It can be found that three methods are called:
- Createbeaninstance() - > instantiation
- Populatebean() - > dependency injection
- Initializebean() - > initialize
Destroy
The destroy phase is called when the container is closed, in ConfigurableApplicationContext#close()
As for xxaware, BeanPostProcessor, BeanFactoryPostProcessor and other classes, they are just a series of extension points for the main process.
Extension point of Bean's life cycle
There are many extension points in the life cycle of Spring beans. It is impossible to list them all here. Only the core extension points are mentioned. This is why Spring has good scalability. It has opened a lot of holes to make a function highly cohesive and loosely coupled as much as possible. Users can use whatever function they need, rather than directly come to a large and comprehensive thing.
Bean level
The implementation classes of these interfaces are based on beans. Only beans that implement these interfaces work.
- BeanNameAware
- BeanFactoryAware
- ApplicationContextAware
- InitializingBean
- DisposableBean
There are also many xxaware, which are not commonly used. The following life cycle tests are not added, such as:
- BeanClassLoaderAware
- EnvironmentAware
- EmbeddedValueResolverAware
- ResourceLoaderAware
- ApplicationEventPublisherAware
- MessageSourceAware
- ServletContextAware
Container level
The implementation classes of these interfaces are Bean independent and will be registered in the Spring container. Their implementation classes are generally called post processors.
These postprocessors will work when any Bean is created by the Spring container
- BeanPostProcessor
- InstantiationAwareBeanPostProcessor (InstantiationAwareBeanPostProcessor inherits BeanPostProcessor)
- The factory post processor interface is also container level. Called immediately after applying the context assembly profile:
- AspectJWeavingEnabler
- ConfigurationClassPostProcessor
- CustomAutowireConfigurer
Common interface
InstantiationAwareBeanPostProcessor
- This class is a sub interface of BeanPostProcessor. There are three common methods:
- postProcessBeforeInstantiation(Class beanClass, String beanName): before bean is instantiated.
- postProcessProperties(PropertyValues pvs, Object bean, String beanName): before bean instantiation, set up properties before calling
- postProcessAfterInstantiation(Class beanClass, String beanName): after bean instantiation
BeanNameAware
- The BeanNameAware interface is designed to make its own beans aware. There is only one method, setBeanName(String name), to obtain its own id or name attribute in the Spring container.
BeanFactoryAware
- This interface has only one method, setBeanFactory(BeanFactory beanFactory), which is used to obtain the BeanFactory in the current environment and can extend all beans in the factory.
ApplicationContextAware
-
The interface has only one method setApplicationContext(ApplicationContext applicationContext), which is used to obtain the ApplicationContext in the current environment and can extend the entire container.
-
Note: sometimes this interface will not be called, which depends on your IOC container: the minimum requirement of Spring IOC container is to implement BeanFactory interface instead of ApplicationContext interface. For those containers that do not implement ApplicationContext interface, the methods defined by ApplicationContextAware corresponding to the life cycle will not be called, Only the container that implements the ApplicationContext interface will be called.
BeanPostProcessor
- postProcessBeforeInitialization(Object bean, String beanName): this method is called before initialization, and AOP of Spring is implemented by it.
- postProcessAfterInitialization(Object bean, String beanName): this method is called after initialization.
InitializingBean
- The interface has only one method called afterPropertiesSet(), which is called after the attribute injection is completed.
- All classes that inherit this interface will execute this method when initializing the bean, and you can configure some properties.
- InitializingBean corresponds to the initialization phase of the lifecycle and is invoked in the invokeInitMethods(beanName, wrappedBean, mbd) method of the source code.
DisposableBean
- This interface is called when an object is destroyed, and can perform some resource destruction operations.
- DisposableBean is similar to InitializingBean, which corresponds to the destruction stage of the life cycle. The ConfigurableApplicationContext#close() method is used as the entrance. The implementation is to get all Bean that implements the DisposableBean interface and then call destroy() method.
Common notes
@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
- @Bean declares a bean, which is used with the @ Configuration annotation
- initMethod: a method called back when declaring bean initialization, which needs to be written by the programmer
- destroyMethod: call back a method when declaring bean destruction, which needs to be written by the programmer
@PostConstruct
- An annotation based initialization method of bean
@PreDestroy
- An annotation based destruction method of bean
case analysis
Declare a bean
@Configuration public class BeanInitAndDestroyConfig { /** * @return There is no bean name specified here. The default is the method name */ @Description("test bean Life cycle of") @Bean(initMethod = "initMethod", destroyMethod = "destroyMethod") public MyService myServiceBeanName() {//Input parameters can inject other dependencies return new MyService(); } } Copy code
- Declare a bean named myServiceBeanName
- initMethod: the initialization method of the bean is: initMethod
- destroyMethod: the bean's destruction method is: destroyMethod
Animal implementation class
- This is just to show that the @ Qualifier annotation can match according to the bean name.
My services
- That is, the interface that is called only once for the current bean
/** * @Description: bean Life cycle testing: these interfaces are only for the current bean * @Author: jianweil * @date: 2021/12/8 9:46 */ public class MyService implements Person, BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean { private Animal animal = null; private ApplicationContext applicationContext; /** *Interface specification method */ @Override public void service() { this.animal.use(); } public MyService() { System.out.println("2. [bean instantiation ]: "+this.getClass().getSimpleName()+"----------Construction method"); } /** *Interface specification method: injection dependency */ @Override @Autowired @Qualifier("dog") public void setAnimal(Animal animal) { System.out.println("5. [bean Attribute assignment]: dog----Dependency injection"); this.animal = animal; } @Override public void setBeanName(String s) { System.out.println("6. Call[ BeanNameAware]--setBeanName:"+s); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("7. Call[ BeanFactoryAware]--setBeanFactory"); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; System.out.println("8. Call[ ApplicationContextAware]--setApplicationContext"); } /** * Initialization 1 */ @PostConstruct public void myInit() { System.out.println("10. [initialization] annotation@PostConstruct Custom initialization method[myInit]"); } /** * Initialization 2 */ @Override public void afterPropertiesSet() throws Exception { System.out.println("11. [initialization] Interface InitializingBean method[afterPropertiesSet]"); } /** * Initialization 3 */ public void initMethod() { System.out.println("12. [initialization] annotation@Bean Custom initialization method[initMethod]"); } /** * Destruction 1 */ @PreDestroy public void myDestroy() { System.out.println("14. [Destroy] annotation@PreDestroy Custom destruction method[myDestroy]"); } /** * Destruction 2 */ @Override public void destroy() throws Exception { System.out.println("15. [Destroy] Interface DisposableBean method[destroy]"); } /** * Destruction 3 */ public void destroyMethod() { System.out.println("16. [Destroy] annotation@Bean Custom destruction method[destroyMethod]"); } } Copy code
- The interface implemented here only works on the life cycle of the current bean (that is, the bean name defined by @ bean above is myDefineBeanName)
Post Processors
- Each bean lifecycle is executed once
- The postprocessor acts on the lifecycle of all bean s in the ioc container.
/** * @Description: todo * @Author: jianweil * @date: 2021/12/20 17:20 */ @Component public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor { @Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { if ("myServiceBeanName".equals(beanName) || "dog".equals(beanName)) { System.out.println("============================InstantiationAwareBeanPostProcessor-start======================"); System.out.println("1. [Container level each bean All callback] call InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() method: beanName by"+beanName); } return null; } @Override public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { if ("myServiceBeanName".equals(beanName) || "dog".equals(beanName)) { System.out.println("3. [Container level each bean All callback] call InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() method: beanName by"+beanName); } return true; } @Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException { if ("myServiceBeanName".equals(beanName) || "dog".equals(beanName)) { System.out.println("4. [Container level each bean All callback] call InstantiationAwareBeanPostProcessor.postProcessProperties() method: beanName by"+beanName); System.out.println("============================InstantiationAwareBeanPostProcessor-end======================"); } return null; } } Copy code
/** * @Description: Post bean initializer: all beans will intercept execution * @Author: jianweil * @date: 2021/12/8 9:46 */ @Component public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { //Here, the beans automatically configured by springboot are filtered out, and only the beans of our project are printed if ("myServiceBeanName".equals(beanName) || "dog".equals(beanName)) { System.out.println("9. [Container level each bean All callback] call BeanPostProcessor.postProcessBeforeInitialization method: beanName by" + beanName); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if ("myServiceBeanName".equals(beanName) || "dog".equals(beanName)) { System.out.println("13. [Container level each bean All callback] call BeanPostProcessor.postProcessAfterInitialization method: beanName by" + beanName); } return bean; } } Copy code
Factory post processor
- Container level, only allowed once
@Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("0. [The container level is called only once] call BeanFactoryPostProcessor.postProcessBeanFactory() method"); } } Copy code
Output results and interpretation of results
- "/ /" marked as interpreted
//The container level factory post processor is only called once immediately after the application context assembly configuration file 0. [The container level is called only once] call BeanFactoryPostProcessor.postProcessBeanFactory() method //Because our life process only prints ("myservicebeanname". Equals (beanname) 𞓜 "dog" Equals (beanname)), all cats only have the construction method printed cat----------Construction method //###############################Life cycle of dog############################################### //Post processor, container level, works on all bean s ============================InstantiationAwareBeanPostProcessor-start====================== 1. [Container level each bean All callback] call InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() method: beanName by dog //Dog instantiation dog----------Construction method //Post processor, container level, works on all bean s 3. [Container level each bean All callback] call InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() method: beanName by dog //Post processor, container level, works on all bean s 4. [Container level each bean All callback] call InstantiationAwareBeanPostProcessor.postProcessProperties() method: beanName by dog ============================InstantiationAwareBeanPostProcessor-end====================== //Post processor, container level, works on all bean s 9. [Container level each bean All callback] call BeanPostProcessor.postProcessBeforeInitialization method: beanName by dog //Post processor, container level, works on all bean s 13. [Container level each bean All callback] call BeanPostProcessor.postProcessAfterInitialization method: beanName by dog //###############################dog's bean is completed and start myServiceBeanName############################################### //Post processor, container level, works on all bean s ============================InstantiationAwareBeanPostProcessor-start====================== 1. [Container level each bean All callback] call InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() method: beanName by myServiceBeanName //instantiation 2. [bean instantiation ]: MyService----------Construction method //Post processor, container level, works on all bean s 3. [Container level each bean All callback] call InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() method: beanName by myServiceBeanName //Post processor, container level, works on all bean s 4. [Container level each bean All callback] call InstantiationAwareBeanPostProcessor.postProcessProperties() method: beanName by myServiceBeanName ============================InstantiationAwareBeanPostProcessor-end====================== //Attribute assignment is dependency injection 5. [bean Attribute assignment]: dog----Dependency injection //At the bean level, bean: myServiceBeanName implements the interface BeanNameAware 6. Call[ BeanNameAware]--setBeanName:myServiceBeanName //bean level 7. Call[ BeanFactoryAware]--setBeanFactory //bean level 8. Call[ ApplicationContextAware]--setApplicationContext //Post processor, container level, acts on all bean s: pre initialization processing 9. [Container level each bean All callback] call BeanPostProcessor.postProcessBeforeInitialization method: beanName by myServiceBeanName //initialization 10. [initialization] annotation@PostConstruct Custom initialization method[myInit] 11. [initialization] Interface InitializingBean method[afterPropertiesSet] 12. [initialization] annotation@Bean Custom initialization method[initMethod] //Post processor, container level, acts on all bean s: Post initialization processing 13. [Container level each bean All callback] call BeanPostProcessor.postProcessAfterInitialization method: beanName by myServiceBeanName //When the container environment is loaded, all bean s can be used 2021-12-21 11:18:42.994 INFO 18956 --- [ main] c.l.s.SpringbootBeanLifecycleApplication : Started SpringbootBeanLifecycleApplication in 0.719 seconds (JVM running for 1.312) //Destroy 14. [Destroy] annotation@PreDestroy Custom destruction method[myDestroy] 15. [Destroy] Interface DisposableBean method[destroy] 16. [Destroy] annotation@Bean Custom destruction method[destroyMethod] Process finished with exit code 0 Copy code
Bean life cycle diagram
The significance of understanding the Spring life cycle is that beans can be used to complete some related operations at a specified time during their lifetime. Generally, some related operations will be performed after the Bean is initialized and before it is destroyed.