Spring Bean life cycle

1. Foreword:

Before we understand the life cycle of Spring Bean, let’s first understand two concepts:
1.1 What is a Bean

In Spring, the objects that form the backbone of your application and
A bean that are managed by the Spring IoC container are called beans.
is an object that is instantiated, assembled, and otherwise managed by
a Spring IoC container. Otherwise, a bean is simply one of many
objects in your application. Beans, and the dependencies among them,
are reflected in the configuration metadata used by a container.
In short, a bean is an object instantiated, assembled, and managed by the Spring IoC container.

1.2 What is the life cycle of Spring Bean

For ordinary Java objects, the object is created when new is used, and then the object can be used. Once the object is no longer used, it is automatically garbage collected by Java.

The objects in Spring are beans. There is no big difference between beans and ordinary Java objects, except that Spring no longer does new by itself.
object, but the IoC container helps us instantiate the object and manage it. Which object we need can be asked by the IoC container. IoC
In fact, it is to solve the coupling problem between objects. The life cycle of Spring Bean is completely controlled by the container.

2. Spring Bean life cycle

The life cycle of Spring Bean we are talking about here mainly refers to singleton beans. For prototype beans, Spring will not manage the subsequent life cycle after it is created and handed over to the user.

Let’s also review what are the scopes of beans in Spring?

singleton: The only bean instance. Beans in Spring are singletons by default. prototype: A new bean instance is created with each request.
request: Each HTTP request will generate a new bean, which is only valid within the current HTTP request.
session: Each HTTP request will generate a new bean, which is only valid within the current HTTP session.
global-session: Global session scope, only in Portlet-based web
It only makes sense in applications, and Spring5 no longer has it. Portlets are small Java Web plug-ins capable of generating snippets of semantic code (for example: HTML). They are based on portlet containers and can handle HTTP requests like servlets. However, unlike servlets, each portlet has a different session.

We know that for ordinary Java objects, their life cycle is:

·Instantiation
·The object is recycled through the garbage collection mechanism when it is no longer used.

As for the life cycle of Spring Bean:

Instantiation Instantiation
Property assignment Populate
Initialization
Destruction

Instantiation -> Attribute assignment -> Initialization -> Destruction

Directly to the final main logic.

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 {<!-- -->
    //Attribute assignment phase
        this.populateBean(beanName, mbd, instanceWrapper);
        //Initialization phase
        exposedObject = this.initializeBean(beanName, exposedObject, mbd);
    } catch (Throwable var18) {<!-- -->
        ...
    }

    ...
}

As for destruction, it is called when the container is closed. For details, see *ConfigurableApplicationContext#close()*

As for BeanPostProcessor, BeanFactoryPostProcessor and other classes, they are just a series of extension points to the four steps of the main process.

3. Extension points of Spring Bean life cycle

There are so many extension points in the Spring Bean life cycle that it is impossible for Lao Zhou to list them all here, only the core extension points. This is why Spring’s scalability is very good. It has opened up a lot of openings to make a certain function highly cohesive and loosely coupled as much as possible. Users can use whichever function they need, rather than directly creating a large and comprehensive thing.

3.1 Bean’s own methods

For example, constructors, getters/setters, and methods specified by init-method and destruction-method, etc., correspond to the four stages of instantiation -> attribute assignment -> initialization -> destruction mentioned above.

3.2 Container-level methods (BeanPostProcessor series of interfaces)

Mainly post-processor methods, such as the InstantiationAwareBeanPostProcessor, BeanPostProcessor interface methods in the figure below. The implementation classes of these interfaces are independent of beans and will be registered in the Spring container. These post-processors will take effect when the Spring container creates any bean.

3.2.1 InstantiationAwareBeanPostProcessor source code analysis

We looked through the source code and found that InstantiationAwareBeanPostProcessor inherits BeanPostProcessor


InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation call point

Object postProcessBeforeInstantiation(Class beanClass, String
beanName)
Return value: If the returned value is not null, then the subsequent Bean creation process [instantiation, initialization afterProperties] will not be executed, but the returned shortcut Bean will be used directly. The normal execution sequence at this time is as follows:
postProcessBeforeInstantiation in the InstantiationAwareBeanPostProcessor interface is called before instantiation.
postProcessAfterInitialization in the BeanPostProcessor interface is called after instantiation.





In short, postProcessBeforeInstantiation is called before doCreateBean, that is, before the bean is instantiated. The English source code comments explain that the return value of this method will replace the original Bean as a proxy, which is also a key point in the implementation of functions such as AOP.

InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation call point

boolean postProcessAfterInstantiation(Object bean, String beanName)
throws BeansException is normally called after instantiation and before executing populateBean.
Return value: If false is returned when there is a specified bean, then subsequent property filling and property dependency injection [populateBean] will not be executed, and subsequent postProcessPropertyValues will not be executed, but initialization and BeanPostProcessor will still be executed.

public PropertyValues postProcessPropertyValues(PropertyValues pvs,
PropertyDescriptor[] pds, Object bean, String beanName)
Called after instantiation, before method applyPropertyValues [property filling]
Return value: If null is returned, subsequent attribute filling, such as dependency injection, etc. will not be performed. If additional attributes are added to the returned pvs, then the corresponding attributes of the class will be filled in later.
pvs: PropertyValues object, used to encapsulate objects of specified classes. Simply put, it is a collection of PropertyValues, which is equivalent to storing the attributes and values of the class in key-value form.
pds: Array of PropertyDescriptor objects. PropertyDescriptor is equivalent to the properties of the storage class, but you can call the set and get methods to set and get the value of the corresponding property.

3.2.2 BeanPostProcessor source code analysis

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

Enter the initialization interface:

Let’s look at it first

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization

First get all post-processors getBeanPostProcessors()
Call the post-processor methods in sequence in the for loop processor.postProcessBeforeInitialization(result, beanName);

Enter the postProcessBeforeInitialization method

org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization

Enter the invokeAwareInterfaces(bean); method. The current bean implements the ApplicationContextAware interface.

ApplicationContextAwareProcessor#postProcessBeforeInitialization First determine whether the bean is various Aware. If it is one of the Aware listed by it, it will obtain the permissions of the Bean factory and import the relevant context into the container. The purpose is to The Bean instance can obtain the relevant context. If it is not listed as Aware, then call invokeAwareInterfaces(bean) to add the context of the relevant interface to the container.

3.3 Factory post-processor methods (BeanFactoryProcessor series of interfaces) include:

AspectJWeavingEnabler, CustomAutowireConfigurer, ConfigurationClassPostProcessor, etc. These are BeanFactoryPostProcessors that have been implemented in the Spring framework and are used to implement certain specific functions.

We know that the key link in Spring IoC container initialization is org.springframework.context.support.AbstractApplicationContext#refresh
In the method, the main process of container creation is in this method. This method is really important! ! !

For factory postprocessor methods see invokeBeanFactoryPostProcessors(beanFactory);
Method, this method handles beans of the BeanFactoryPostProcessor interface. The calling method is as follows:

Follow the most important method. Although the code is long, the logic is quite satisfactory.

BeanFactoryPostProcessor: The parent interface for all processing BeanFactory
BeanDefinitionRegistryPostProcessor: implements the interface of BeanFactoryPostProcessor: interface


Flow Description:

1. Call the BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(registry) method. The parameters passed in beanFactoryPostProcessors are processed first. Then obtain the container registration, and process these beans according to PriorityOrdered interface, Ordered, and instances without sorting interface respectively.
2. Call the BeanFactoryPostProcessor#postProcessBeanFactory(beanFactory) method. Note: BeanDefinitionRegistryPostProcessor belongs to the BeanFactoryPostProcessor sub-interface. First process the postProcessBeanFactory(beanFactory) method belonging to the BeanDefinitionRegistryPostProcessor interface instance, and then obtain the container registration. These beans are processed separately according to PriorityOrdered interface, Ordered, and instances without sorting interface.

3.4 Bean-level life cycle methods

It can be understood that the Bean class directly implements the interface methods, such as BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean and other methods. These methods only take effect on the current Bean.

3.4.1 Aware type interface

The function of the Aware type interface is to allow us to get some resources in the Spring container. Basically, you can know the meaning by name. The name before Aware is what resources can be obtained. For example, BeanNameAware can get BeanName, and so on. Note the timing of the call: all Aware methods are called before the initialization phase.

There are many Aware interfaces, and they are also classified here to help everyone remember them. The Aware interface can be divided into two groups. As for why they are so divided, please see the source code analysis below for details. The following order of arrangement is also the execution order of the Aware interface. Interfaces whose names are obvious will not be explained.

Aware Group1

BeanNameAware

BeanClassLoaderAware

BeanFactoryAware

Aware Group2

EnvironmentAware

EmbeddedValueResolverAware

Not many people may know this. Implementing this interface can obtain the Spring EL parser. It can be used when user-defined annotations need to support SPEL expressions, which is very convenient.

ApplicationContextAware(ResourceLoaderAware/ApplicationEventPublisherAware/MessageSourceAware)
These interfaces may make people a little confused. In fact, these interfaces can be remembered together. Their return values are essentially the current ApplicationContext object, because ApplicationContext is a composite interface, as follows:

Aware call timing source code analysis

It can be seen that not all Aware interfaces are called in the same way. Bean××Aware is called directly in the code, and ApplicationContext related Aware is implemented through BeanPostProcessor#postProcessBeforeInitialization(). If you are interested, you can take a look at the source code of the ApplicationContextAwareProcessor class. It determines whether the currently created Bean implements the relevant Aware method. If it does, the callback method will be called to pass the resource to the Bean.

The calling timing of BeanPostProcessor can also be reflected here, surrounding the invokeInitMethods method, which also illustrates the execution before and after the initialization phase.

Regarding the execution order of the Aware interface, you only need to remember that the first group is executed before the second group.

3.4.2 Life cycle interface

As for the remaining two life cycle interfaces, it is very simple. Instantiation and attribute assignment are all done by Spring to help us. There are two life cycle stages of initialization and destruction that can be implemented by ourselves.

InitializingBean corresponds to the initialization phase of the life cycle and is called in the invokeInitMethods(beanName, wrappedBean, mbd); method of the above source code.
One thing to note is that because the Aware method is executed before the initialization method, you can safely use the resources obtained by the Aware interface in the initialization method. This is also a common way for us to customize and extend Spring.
In addition to implementing the InitializingBean interface, you can also specify the initialization method through annotations or xml configuration. As for the calling order of these definition methods, it is not necessary to remember. Because these methods all correspond to the same life cycle, but are implemented in different ways, we generally only use one of them.
DisposableBean is similar to InitializingBean and corresponds to the destruction phase of the life cycle. The ConfigurableApplicationContext#close() method is used as the entry point. The implementation is to loop through all the beans that implement the DisposableBean interface and then call For its destroy() method, if you are interested, you can follow the source code yourself.

3.5 Spring Bean life cycle flow chart

4. Description of common interfaces

4.1 BeanNameAware

This interface has only one method setBeanName(String name), which is used to obtain the id or name of the bean.

4.2 BeanFactoryAware

This interface has only one method setBeanFactory(BeanFactory beanFactory), which is used to obtain the BeanFactory in the current environment.

4.3 ApplicationContextAware

This interface has only one method setApplicationContext(ApplicationContext applicationContext), which is used to obtain the ApplicationContext in the current environment.

4.4 InitializingBean

This interface has only one method afterPropertiesSet(), which is called after the property injection is completed.

4.5 DisposableBean

This interface has only one method destroy(), which is called when the container is destroyed and before the user-specified destroy-method.

4.6 BeanPostProcessor

This interface has two methods:

postProcessBeforeInitialization(Object bean, String beanName):Call this method before initialization
postProcessAfterInitialization(Object bean, String beanName): Call this method after initialization
We can know from the method signature that we can filter out the beans we need to customize by beanName.

4.7 InstantiationAwareBeanPostProcessor

This class is a sub-interface of BeanPostProcessor. The following three methods are commonly used:

postProcessBeforeInstantiation(Class beanClass, String beanName): Called before bean instantiation
postProcessProperties(PropertyValues pvs, Object bean, String beanName): Called after bean instantiation and before setting properties
postProcessAfterInstantiation(Class beanClass, String beanName):Called after bean instantiation

5. Code demonstration

Idea: Create a class UserBean, let it implement several special interfaces, observe the thread call stack at the constructor and interface method interruption point of the interface implementation, and analyze the triggering timing of key points in Bean object creation and management.

5.1 UserBean class

@Component
public class UserBean implements InitializingBean, BeanNameAware, DisposableBean, ApplicationContextAware {<!-- -->
private int id;

private String name;

public UserBean(int id, String name) {<!-- -->
this.id = id;
this.name = name;
System.out.println("2. Call the constructor");
}

public int getId() {<!-- -->
return id;
}

public void setId(int id) {<!-- -->
this.id = id;
System.out.println("5. Property injection id");
}

public String getName() {<!-- -->
return name;
}

public void setName(String name) {<!-- -->
this.name = name;
System.out.println("5. Property injection name");
}

@Override
public void setBeanName(String name) {<!-- -->
System.out.println("6. Call the BeanNameAware.setBeanName() method");
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {<!-- -->
UserBean userBean = (UserBean) applicationContext.getBean("userBean");
System.out.println(userBean);
System.out.println("7. Call BeanNameAware.setBeanName() method");
}

@Override
public void afterPropertiesSet() throws Exception {<!-- -->
System.out.println("9. Call the InitializingBean.afterPropertiesSet() method");
}

public void myInit() {<!-- -->
System.out.println("10. Call the init-method method");
}

@Override
public void destroy() throws Exception {<!-- -->
System.out.println("12. Call the DisposableBean.destroy() method");
}

public void myDestroy() {<!-- -->
System.out.println("13. Call the destroy-method method");
}

@Override
public String toString() {<!-- -->
return "UserBean{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}

5.2 InstantiationAwareBeanPostProcessor interface implementation class
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {<!-- -->
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {<!-- -->
if ("userBean".equals(beanName)) {<!-- -->
System.out.println("1. Call the InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() method");
}
return null;
}

@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {<!-- -->
if ("userBean".equals(beanName)) {<!-- -->
UserBean userBean = (UserBean) bean;
System.out.println("3. Call the InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() method");
System.out.println(userBean);
}
return true;
}

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {<!-- -->
if ("userBean".equals(beanName)) {<!-- -->
System.out.println("4. Call the InstantiationAwareBeanPostProcessor.postProcessProperties() method");
}
return null;
}
}

5.3 BeanPostProcessor interface implementation class
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {<!-- -->
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {<!-- -->
if ("userBean".equals(beanName)) {<!-- -->
System.out.println("8. Call BeanPostProcessor.postProcessBeforeInitialization() method");
}
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {<!-- -->
if ("userBean".equals(beanName)) {<!-- -->
System.out.println("11. Call BeanPostProcessor.postProcessAfterInitialization() method");
}
return bean;
}
}

5.4 BeanFactoryPostProcessor interface implementation class
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {<!-- -->
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {<!-- -->
System.out.println("0. Call BeanFactoryPostProcessor.postProcessBeanFactory() method");
}
}

5.5 applicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd
">

<bean class="com.riemann.test.MyInstantiationAwareBeanPostProcessor" />

<bean id="userBean" class="com.riemann.test.UserBean" init-method="myInit" destroy-method="myDestroy">
<!-- Constructor injection -->
<constructor-arg index="0" type="int">
<value>1</value>
</constructor-arg>
<constructor-arg index="1" type="java.lang.String">
<value>WeChat public account [Laozhou Chat Architecture]</value>
</constructor-arg>

<!-- setter method injection -->
<property name="id" value="2"/>
<property name="name" value="riemann"/>
</bean>

<bean class="com.riemann.test.MyBeanPostProcessor" />

<bean class="com.riemann.test.MyBeanFactoryPostProcessor" />
\t
</beans>

5.6 Test class
public class BeanLifeCycleTest {<!-- -->
public static void main(String[] args) {<!-- -->
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserBean user = (UserBean) applicationContext.getBean("userBean");
((AbstractApplicationContext) applicationContext).close();
}
}

5.7 Console result printing