Welcome to pay attention to my wechat public number [old Week chat architecture], The principle of Java backend mainstream technology stack, source code analysis, architecture and a variety of Internet high concurrency, high performance, high availability solutions.

One, foreword

Today we are going to talk about the life cycle of Spring beans. Because the life cycle of Spring Bean is the most important concept besides IoC and AOP, we must take it. But Spring source code is more complex, follow follow don’t know where to go, it is not easy to take down. This is true, and online on a variety of paste process source code, for beginners is really a face meng force, like the word all understand, but even in a piece do not know the meaning, too around.

In this article, Lao Zhou tries to make it easy for more friends to understand the life cycle of Spring Bean, and have the idea of continuing to study it. Then my purpose of writing this article has also been achieved.

Before we get into the life cycle of Spring beans, let’s understand two concepts:

1.1 What is a Bean

Take a look at the official documentation for the Spring Framework:

In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean 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, beans are objects instantiated, assembled, and managed by the Spring IoC container.

1.2 What is the Spring Bean lifecycle

For normal Java objects, the object is created when new, and then the object can be used. Once the object is no longer in use, It is automatically garbage collected by Java.

The objects in Spring are beans. Beans are not much different from normal Java objects, except that Spring no longer uses the new object itself. Instead, the IoC container helps us instantiate and manage the object. IoC is all about coupling between objects, and the lifecycle of Spring beans is completely controlled by the container.

Second, the life cycle of Spring Beans

For prototype beans, Spring does not manage the rest of the life cycle after they are created and given to the user.

Let’s also review the scope of beans in Spring.

  • singleton: a unique bean instance. Beans in Spring are singleton by default.
  • prototype: A new bean instance is created for each request.
  • requestEach HTTP request generates a new bean that is valid only within the current HTTP request.
  • session: Each HTTP request generates a new bean that is valid only for the current HTTP session.
  • global-session: global session scope, which only makes sense in portlet-based web applications, is missing in Spring5. Portlets are small Java Web plug-ins that can generate snippets of semantic code, such as 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 collected through the garbage collection mechanism when it is no longer in use

For the Spring Bean lifecycle:

  • Instantiate the Instantiation
  • Property assignment Populate
  • Initialize the Initialization
  • Destruction of Destruction

Instantiate -> Attribute Assignment -> Initialize -> Destroy

There are only four steps. Doesn’t it feel easy to disassemble? Unlike others who write BeanPostProcessor and BeanFactoryPostProcessor, you may not even know what you are writing after a short period of time, let alone the reader’s head.

Lao zhou was supposed to create process through Bean entrance AbstractApplicationContext# refresh () method of finishBeanFactoryInitialization (the beanFactory) take you to the source code, I thought I’d rather not bring in too much code and go straight 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) { ... }... }Copy the code

As for destruction, is invoked when the container close, see ConfigurableApplicationContext# close ()

Isn’t it refreshing? As for BeanPostProcessor, BeanFactoryPostProcessor, and the rest of the classes, Mr. Chou saw them as just a series of extension points to the four steps of the main process.

Extension points for the lifecycle of Spring beans

There are so many extension points in the life cycle of Spring beans that it is impossible to list them all here, just the core extension points. That’s why Spring is so extensible, opening up as many doors as possible to make a feature as cohesive and loosely coupled as possible, so that users can use whatever they want, rather than just one big, all-in-one thing.

3.1 Methods of the Bean itself

For example, constructor, getter/setter, init-method and destory-method specify methods, which are instantiated -> property assignment -> initialization -> destruction.

3.2 Container-level Approach (BeanPostProcessor Series of interfaces)

Mainly after the handler method, such as the image below InstantiationAwareBeanPostProcessor, BeanPostProcessor interface methods. The implementation classes for these interfaces are bean-independent and registered with the Spring container. These post-handlers come into play whenever the Spring container creates any beans.

3.2.1 InstantiationAwareBeanPostProcessor source analysis

We found InstantiationAwareBeanPostProcessor search source is inherited BeanPostProcessor

  • InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiationCall the point

Object postProcessBeforeInstantiation(Class<? > beanClass, String beanName) return value: If null is not returned, the afterProperties process will not be executed, but will be directly used by the returned shortcut Bean. The postProcessBeforeInstantiation InstantiationAwareBeanPostProcessor interface, call before instantiation. The postProcessAfterInitialization BeanPostProcessor interface, call after instantiation.

Anyhow, postProcessBeforeInstantiation before doCreateBean calls, call before bean instantiation, English source annotation explains the return value of this method will replace the original beans as an agent, This is also the key to implementing features such as AOP.

  • InstantiationAwareBeanPostProcessor#postProcessAfterInstantiationCall the point

boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException Normally call the return value after instantiation but before populateBean execution: If the specified bean is returned with false, subsequent property populating and property dependency injection will not be performed. And the subsequent postProcessPropertyValues would not perform, but initialization and BeanPostProcessor will still be executed.

public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) after instantiation, before applyPropertyValues returns: If null is returned, no subsequent property populations, such as dependency injection, will be performed. If the returned PVS have additional attributes added, they will be populated with the corresponding property of the class. PVS: PropertyValues object, used to encapsulate the object of a specified class. In simple terms, it is a collection of PropertyValues, which store the properties and values of the class in key-value form. PDS: An array of PropertyDescriptor objects. Property Descriptors are used to store properties of classes, but they can be set and obtained by calling set and GET methods.

3.2.2 Source code analysis of BeanPostProcessor

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 the post-processors getBeanPostProcessors()
  • The methods of the post-processor are called in turn in the for loopprocessor.postProcessBeforeInitialization(result, beanName);
  • Enter the postProcessBeforeInitialization method

org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization

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

  • ApplicationContextAwareProcessor#postProcessBeforeInitializationFirst, check whether the bean is a variety of Aware. If it is the Aware listed by it, then obtain the permission of the bean factory and import the relevant context into the container. The purpose is that the bean instance can obtain the relevant context, if not the Aware listed by it, then callinvokeAwareInterfaces(bean)To add the context of the relevant interface to the container.

3.3 BeanFactoryProcessor Approach (A series of Interfaces)

Including AspectJWeavingEnabler, CustomAutowireConfigurer, ConfigurationClassPostProcessor, etc. These are beanFactoryPostProcessors already implemented in the Spring framework to implement specific functionality.

We know that the Spring IoC container initialization of the key links in the org. Springframework. Context. Support. AbstractApplicationContext# refresh method, The main process of container creation is in this method, this method is really important!!

Methods for factory after processor Lao zhou directly take you to see here invokeBeanFactoryPostProcessors (the beanFactory); Method that handles beans from the BeanFactoryPostProcessor interface. The call method is as follows:

Follow the most important method, the code is long, but the logic is neat.

Spring BeanFactoryPostProcessor: all the father of the BeanFactory interface BeanDefinitionRegistryPostProcessor: implements the spring BeanFactoryPostProcessor interface interface

Process description:

  • Call BeanDefinitionRegistryPostProcessor# postProcessBeanDefinitionRegistry (registry) method. Parameter beanFactoryPostProcessors incoming priority. It then gets those registered by the container and treats those beans as instances of the PriorityOrdered interface, Ordered interface, and unordered interface.
  • Call the BeanFactoryPostProcessor#postProcessBeanFactory(beanFactory) method. Note: BeanDefinitionRegistryPostProcessor belongs to spring BeanFactoryPostProcessor interface. Processing belongs to the first BeanDefinitionRegistryPostProcessor interface instance postProcessBeanFactory (the beanFactory) method, and get registered vessel. These beans are processed as instances of the PriorityOrdered interface, Ordered, and unordered interfaces.

3.4 Bean-level lifecycle methods

Can be understood as Bean classes directly implement interface methods, such as BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean, These methods only apply to the current Bean.

3.4.1 Aware type interface

The purpose of the Aware type interface is to give us access to some of the resources in the Spring container. The name before Aware is the resource you can get. For example, BeanNameAware can get BeanName, and so on. Call timing is important: All Aware methods are called before the initialization phase.

There are many Aware interfaces, and there are also categories to help you remember them. The Aware interface can be divided into two groups. For why, see the source code analysis below. The following order is also the execution order of Aware interfaces. Interfaces that can be seen and understood will not be explained.

Aware Group1

  • BeanNameAware
  • BeanClassLoaderAware
  • BeanFactoryAware

Aware Group2

  • EnvironmentAware
  • EmbeddedValueResolverAwareNot many people know this, but implementing this interface can get the Spring EL parser, which can be used when the user’s custom annotations need to support SPEL expressions.
  • ApplicationContextAware(ResourceLoaderAware/ApplicationEventPublisherAware/MessageSourceAware)

These interfaces can be a bit confusing, but they can actually be remembered together. The return value is essentially the current ApplicationContext object, because ApplicationContext is a composite interface, as follows:

Aware call timing source code analysis

You can see that not all Aware interfaces are invoked in the same way. Beans of xx Aware are called directly in your code, is Aware of ApplicationContext through BeanPostProcessor# postProcessBeforeInitialization () implementation. Interested can look at our ApplicationContextAwareProcessor this class’s source code, is whether the current create Bean implements Aware of related methods, if implemented will call the callback method transfer resources to a Bean.

The timing of the invocation of the BeanPostProcessor can also be seen here, enclosing the invokeInitMethods method, which is executed before and after the initialization phase.

In terms of the execution order of Aware interfaces, it’s really just a matter of remembering that the first group is executed before the second.

3.4.2 Lifecycle Interface

The remaining two lifecycle interfaces are simple, instantiation and attribute assignment are Spring’s help, and can be implemented by itself in the two lifecycle phases of initialization and destruction.

  • InitializingBeanCorresponding to the initialization phase of the lifecycle, in the source code aboveinvokeInitMethods(beanName, wrappedBean, mbd);Method.

One thing to note is that since Aware methods are executed before the initialization method, it is safe to use the Aware interface to fetch resources in the initialization method, which is how we often customize Spring extensions. In addition to implementing the InitializingBean interface, you can also specify the initialization methods through annotations or XML configuration. It is not necessary to remember the order in which these definitions are called. Since these methods correspond to the same life cycle, but are implemented in different ways, we generally use only one of them.

  • DisposableBeanSimilar to the InitializingBean, corresponding to the destruction phase of the lifecycle toConfigurableApplicationContext#close()Method, which can be implemented by looping through all beans that have implemented the DisposableBean interface and then calling its destroy() method, you can follow the source code if you are interested.

3.5 Spring Bean lifecycle Flowchart

4. Description of common interfaces

4.1 BeanNameAware

The interface has only one method, setBeanName(String Name), to get the id or name of the bean.

4.2 BeanFactoryAware

The interface has only one method, setBeanFactory(BeanFactory BeanFactory), to get the BeanFactory in the current environment.

4.3 ApplicationContextAware

The interface has only one method, setApplicationContext(ApplicationContext ApplicationContext), to get the ApplicationContext in the current environment.

4.4 InitializingBean

The interface has only one method, afterPropertiesSet(), which is called after property injection is complete.

4.5 DisposableBean

The interface has only one method destroy(), which is called at container destruction time, before the user-specified destroy-method.

4.6 BeanPostProcessor

This interface has two methods:

  • postProcessBeforeInitialization(Object bean, String beanName)In:Before initializationCalling this method
  • postProcessAfterInitialization(Object bean, String beanName)In:After initializationCalling this method

We know from method signatures that we can use beanName to filter out beans that we need to personalize.

4.7 InstantiationAwareBeanPostProcessor

This class is a subinterface of BeanPostProcessor. The following methods are commonly used:

  • postProcessBeforeInstantiation(Class beanClass, String beanName): in the beanBefore instantiationcall
  • postProcessProperties(PropertyValues pvs, Object bean, String beanName): in the beanAfter instantiation, before setting propertiescall
  • postProcessAfterInstantiation(Class beanClass, String beanName): in the beanAfter instantiationcall

Five, code demonstration

Create a class UserBean to implement several special interfaces, and observe the thread call stack in the constructor of interface implementation and interface method breakpoints, and analyze the trigger time of Bean object creation and management key points.

5.1 the 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(a) {
		return id;
	}

	public void setId(int id) {
		this.id = id;
		System.out.println("5. Attribute injection ID");
	}

	public String getName(a) {
		return name;
	}

	public void setName(String name) {
		this.name = name;
		System.out.println("5. Attribute injection name");
	}

	@Override
	public void setBeanName(String name) {
		System.out.println("6. Call 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(a) throws Exception {
		System.out.println("9. Call InitializingBean. AfterPropertiesSet () method");
	}

	public void myInit(a) {
		System.out.println("10. Call init-method method");
	}

	@Override
	public void destroy(a) throws Exception {
		System.out.println("12. Call DisposableBean.destroy());
	}

	public void myDestroy(a) {
		System.out.println("13. Call destroy-method");
	}

	@Override
	public String toString(a) {
		return "UserBean{" +
				"id=" + id +
				", name='" + name + '\' ' +
				'} '; }}Copy the code

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 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 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 InstantiationAwareBeanPostProcessor. PostProcessProperties () method");
		}
		return null; }}Copy the code

5.3 BeanPostProcessor Interface implementation classes

@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");
		}
		returnbean; }}Copy the code

5.4 BeanFactoryPostProcessor interface implementation classes

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		System.out.println("0. Call spring BeanFactoryPostProcessor. PostProcessBeanFactory () method"); }}Copy the code

5.5 applicationContext. XML


      
<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 official Account [Lao Zhou Chat structure]</value>
		</constructor-arg>

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

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

	<bean class="com.riemann.test.MyBeanFactoryPostProcessor" />
	
</beans>
Copy the code

5.6 the 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(); }}Copy the code

5.7 Console Result Printing