1. The introduction

“Can you describe the life cycle of Spring beans?” Spring Spring Spring Spring Spring Spring Spring Spring Spring

When I was preparing for the interview, I searched online for answers, and most of them were based on the process shown in the picture below.

But when I first saw it, I had a lot of trouble, “Aware, BeanPostProcessor…… What are all these? And there are so many steps. How do you memorize them?” .

In order to remember this process, we need to understand it first. In this article, we will help understand the Bean life cycle from the following two aspects:

  1. Lifecycle overview flow: The lifecycle of the Bean is summarized and understood in code;

  2. The role of extension points: Details the role of extension points involved in the Bean life cycle.

2. Outline lifecycle processes

The Bean life cycle can be summarized as four phases:

  1. Instantiation
  2. Attribute assignment (Populate)
  3. Initialization
  4. To destroy

  1. Instantiate: Step 1, instantiate a bean object;

  2. Property assignment: Step 2, set the bean’s properties and dependencies;

  3. Initialization: There are many steps from Step 3 to step 7. Step 5 and Step 6 are initialization operations, step 3 and Step 4 are performed before initialization, and Step 7 is performed after initialization.

  4. Destroy: Steps 8-10, 8 is not really destroy (it is not used yet), but register the call interface related to destroy before using it, in order to execute the corresponding method when steps 9 and 10 actually destroy the bean.

The doCreateBean() method executes each of the four phases in sequence:

// AbstractAutowireCapableBeanFactory.java
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
    throws BeanCreationException {

    // 1. Instantiate
    BeanWrapper instanceWrapper = null;
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    
    Object exposedObject = bean;
    try {
        // 2. Attribute assignment
        populateBean(beanName, mbd, instanceWrapper);
        // 3. Initialize
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }

    // 4. Destroy - Register callback interface
    try {
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }

    return exposedObject;
}
Copy the code

Since initialization involves steps 3 to 7, it is quite complicated, so let’s step into the initializeBean() method to see the process in detail (the serial number of the annotation corresponds to the serial number in the figure) :

// AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    // 3. Check Aware related interfaces and set related dependencies
    if(System.getSecurityManager() ! =null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        invokeAwareMethods(beanName, bean);
    }

    // 4. BeanPostProcessor preprocessing
    Object wrappedBean = bean;
    if (mbd == null| |! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); }// 5. If InitializingBean interface is implemented, call afterPropertiesSet() method
    // 6. If the user-defined init-method method is configured, run the command
    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw newBeanCreationException( (mbd ! =null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
    }
    // 7. BeanPostProceesor
    if (mbd == null| |! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }return wrappedBean;
}
Copy the code

In the invokInitMethods() method, the InitializingBean interface and init-method methods are checked, and the destruction process is similar:

// DisposableBeanAdapter.java
public void destroy(a) {
    // 9. To implement the DisposableBean interface, execute the destory() method
    if (this.invokeDisposableBean) {
        try {
            if(System.getSecurityManager() ! =null) {
                AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                    ((DisposableBean) this.bean).destroy();
                    return null;
                }, this.acc);
            }
            else {
                ((DisposableBean) this.bean).destroy(); }}}// 10. If the customized detory-method method is configured, run the command
    if (this.destroyMethod ! =null) {
        invokeCustomDestroyMethod(this.destroyMethod);
    }
    else if (this.destroyMethodName ! =null) {
        Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
        if(methodToInvoke ! =null) { invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke)); }}}Copy the code

From the source code of Spring, we can intuitively see the execution process, and we can remember the process from these four stages: instantiation, attribute assignment, initialization, and destruction. Among them, initialization is more detailed, involving the concepts of Aware, BeanPostProcessor, InitializingBean and init-method. These are extension points that Spring provides, and their role is covered in the next section.

3. Function of extension points

3.1 Aware interface

If Spring detects that the bean implements the Aware interface, it will inject the appropriate dependencies into it. So by having the bean implement the Aware interface, you can get the corresponding Spring container resources in the bean.

The Aware interfaces provided in Spring are:

  1. BeanNameAware: Inject the current bean corresponding to beanName;
  2. BeanClassLoaderAware: inject the ClassLoader that loads the current bean;
  3. BeanFactoryAware: Inject a reference to the current BeanFactory container.

Its code implementation is as follows:

// AbstractAutowireCapableBeanFactory.java
private void invokeAwareMethods(final String beanName, final Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
        if (bean instanceof BeanClassLoaderAware) {
            ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
            
        }
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); }}}Copy the code

The Aware interface is also provided for containers of type BeanFactory, and for containers of type ApplicationContext, the Aware interface is injected via BeanPostProcessor. But its role is still to inject dependencies.

  1. EnvironmentAware: infuse Enviroment, generally used to obtain configuration properties;
  2. EmbeddedValueResolverAware: injection EmbeddedValueResolver (Spring EL parser), commonly used in parameter parsing;
  3. ApplicationContextAware (ResourceLoader ApplicationEventPublisherAware MessageSourceAware) : injection ApplicationContext container itself.

Its code implementation is as follows:

// ApplicationContextAwareProcessor.java
private void invokeAwareInterfaces(Object bean) {
    if (bean instanceof EnvironmentAware) {
        ((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
    }

    if (bean instanceof EmbeddedValueResolverAware) {
        ((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);
    }

    if (bean instanceof ResourceLoaderAware) {
        ((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);
    }

    if (bean instanceof ApplicationEventPublisherAware) {
        ((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);
    }

    if (bean instanceof MessageSourceAware) {
        ((MessageSourceAware)bean).setMessageSource(this.applicationContext);
    }

    if (bean instanceof ApplicationContextAware) {
        ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext); }}Copy the code

3.2 BeanPostProcessor

BeanPostProcessor is a powerful Spring extension point for modifying beans that works on all beans in the container and is defined as follows:

public interface BeanPostProcessor {

	// Initialize the preprocessing
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	// initialize post-processing
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		returnbean; }}Copy the code

Common scenarios are as follows:

  1. For the implementation class that marks the interface, customize the processing. ApplicationContextAwareProcessor section 3.1 say, for example, for them into corresponding rely on; For another example, a custom class that implements a decryption interface will decrypt its attributes.
  2. Provides a proxy implementation for the current object. The Spring AOP feature, for example, generates a proxy class for an object and then returns it.
// AbstractAutoProxyCreator.java
public Object postProcessBeforeInstantiation(Class
        beanClass, String beanName) {
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if(targetSource ! =null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        // Return the proxy class
        return proxy;
    }

    return null;
}
Copy the code

3.3 InitializingBean and init – method

Initializingbeans and init-Method are extension points Spring provides for bean initialization.

The InitializingBean interface is defined as follows:

public interface InitializingBean {
	void afterPropertiesSet(a) throws Exception;
}
Copy the code

Write the initialization logic in the afterPropertiesSet() method.

Specify init-method, specify the initialization method:

<?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.xsd">

    <bean id="demo" class="com.chaycao.Demo" init-method="init()"/>
    
</beans>
Copy the code

DisposableBean and Destory-Method are similar to the above and will not be described.

4. To summarize

To summarize how to remember the life cycle of Spring beans:

  • The first stage is instantiation, attribute assignment, initialization and destruction.

  • The specific operations of initialization include dependency injection of Aware interface, BeanPostProcessor processing before and after initialization, InitializingBean initialization and init-method initialization.

  • For specific destruction operations, you can register the relevant destruction callback interface, and finally DisposableBean and destory-method.

Reference 5.

  1. Stop asking about the life cycle of Spring Beans!
  2. Talk about some of spring’s extension mechanisms

If you like my article, you can scan the code and follow my public account: “Grass Niazi”.