Spring Bean lifecycle

Posted by abnfire on Sat, 08 Jan 2022 12:42:26 +0100

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();
        }

    }
}

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) {
        ...
    }

    ...
}

It can be found that three methods are called:

  1. Createbeaninstance() - > instantiation
  2. Populatebean() - > dependency injection
  3. 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();
    }
}
  • 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]");
    }
}
  • 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;
    }
}
/**
 * @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;
    }
}

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");
    }
}

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

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.

Topics: Java Spring Algorithm Back-end