Bean life cycle
preface
For ordinary Java objects, the object is created when it is new, and is recycled by the garbage collection mechanism when it has no reference. For objects managed by the Spring IoC container, their life cycle is completely controlled by the container. The life cycle of each Bean in Spring is as follows:
1, Instantiate Bean
For the BeanFactory container, when the customer requests a bean that has not been initialized from the container, or needs to inject another dependency that has not been initialized when initializing the bean, the container will call the doCreateBean method for instantiation. For the ApplicationContext container, all beans will be instantiated after the container is started. The container instantiates by obtaining the information in the BeanDefinition object. And this step is only a simple instantiation without dependency injection. The instantiated object is wrapped in the BeanWrapper object. BeanWrapper provides an interface to set object properties, thus avoiding the use of reflection mechanism to set properties
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { // Instantiate bean to BeanWrapper. Bean wrapper BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { // Instantiation: Reflection and factory; instanceWrapper = createBeanInstance(beanName, mbd, args); }
2, Set object properties (dependency injection)
The instantiated object is encapsulated in the BeanWrapper object, and the object is still in a native state without dependency injection. Next, Spring performs dependency injection according to the information in BeanDefinition.
And complete dependency injection through the interface for setting properties provided by BeanWrapper.
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { //Undertake the above // Initializing an instance of a Bean Object exposedObject = bean; try { // Populate bean s. populateBean(beanName, mbd, instanceWrapper); // Populate Bean properties // Initialize bean exposedObject = initializeBean(beanName, exposedObject, mbd); // Initialize the Bean and enter this method (3) }
3, initializeBean
initializeBean, you enter the next stage:
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { // Call Aware method invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { // Post processor of calling bean wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { // Call the initialized method invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { // Call AfterInitialization of the bean's post processor. Place to implement AOP and dynamic agent wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; // Return wrapper class }
3.1 calling Aware interface
Call Aware interface to inject desired attributes into Bean
private void invokeAwareMethods(String beanName, Object bean) { if (bean instanceof Aware) { // Aware of BeanName if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } // Aware of BeanClass if (bean instanceof BeanClassLoaderAware) { ClassLoader bcl = getBeanClassLoader(); if (bcl != null) { ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); } } // Aware of BeanFactory if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } } }
Spring will detect whether the object implements the xxxAware interface and inject the relevant xxxAware instance into the bean.
If the Bean implements the BeanNameAware interface, Spring passes the ID of the Bean to the setBeanName() method (the implementation of BeanNameAware is mainly to obtain the ID of the Bean through the reference of the Bean, which is rarely used in general business)
If the Bean implements the BeanFactoryAware interface, Spring will call the setbeandarty (BeanFactory BF) method and pass in the BeanFactory container instance as a parameter. (the main purpose of implementing BeanFactoryAware is to obtain the Spring container, such as Bean publishing events through the Spring container)
If the Bean implements the ApplicationContextAware interface, the Spring container will call the setApplicationContext(ApplicationContext ctx) method and pass the y application context as a parameter (the function is similar to that of BeanFactory in order to obtain the Spring container. The difference is that the Spring container will pass itself as the parameter of setApplicationContext when calling setApplicationContext method, and the Spring container needs the programmer to specify (inject) the parameter BeanFactory in setBeanDactory before calling setBeanDactory) 6 If the Bean implements the BeanPostProcess interface, Spring will call their postProcessBeforeInitialization method (to enhance the Bean instance after it is successfully created, such as modifying the Bean and adding a function)
3.2 pre processing of calling BeanPostProcessor
After the above steps, the bean object has been constructed correctly, but if you want to do some custom processing before the object is used, you can implement it through the BeanPostProcessor interface.
This interface provides two functions:
• postProcessBeforeInitialzation( Object bean, String beanName )
The bean object currently being initialized will be passed in, and we can do any processing on this bean.
This function will be executed before initializationbean, so it is called preprocessing.
The injection of all Aware interfaces is completed in this step.
• postProcessAfterInitialzation( Object bean, String beanName )
The bean object currently being initialized will be passed in, and we can do any processing on this bean.
This function will be executed after initializationbean is completed, so it is called post-processing.
What is called here is the pre-processing postprocessbeforeinitialization of Bean's post processor.
3.3 invokeInitMethods
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isTraceEnabled()) { logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { // The method executed after setting the attribute is actually to set some states AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { ((InitializingBean) bean).afterPropertiesSet(); return null; }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null && bean.getClass() != NullBean.class) { String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { // Call custom initialization method invokeCustomInitMethod(beanName, bean, mbd); } } }
InitializingBean and init method will enter this stage after the preprocessing of BeanPostProcessor is completed.
3.3.1 afterPropertiesSet()
The InitializingBean interface has only one function: at this stage, we can also add custom logic before the formal construction of the bean is completed, but it is different from pre-processing. Because this function does not pass in the current bean object, we can't deal with the object itself at this step, so we can only add some additional logic. To use it, we need to let the bean implement the interface and write the logic to be added in the function. Then, Spring will detect whether the current bean implements the interface after the preprocessing is completed, and execute the afterpropertieset function.
3.3.2 invokeCustomInitMethod
Of course, in order to reduce the intrusion to the client code, spring provides the bean configuration with the init method attribute, which specifies the name of the function to be executed at this stage. Spring will execute the functions we set in the initialization phase. Init method essentially still uses the InitializingBean interface.
3.4 post processing of calling BeanPostProcessor
When this step is reached, the Bean is ready and stays in the context of the application until it is destroyed.
4 destory
Like init method, by specifying a function for destroy method, the specified logic can be executed before the bean is destroyed.
Article reference from: https://www.zhihu.com/question/38597960/answer/247019950