All extensible points in the Bean's life cycle in the Spring container

Keywords: Java Spring Container

1. Background

In this article, I summarized almost all the extension interfaces of Spring & springboot, as well as the usage scenarios of each extension point. And sorted out the sequential call graph of all extensible points from being loaded to the final initialization of a bean in spring. Thus, we can also see how beans are loaded into the spring container step by step.

2. Extensible interface startup call sequence diagram

The following is the calling sequence of all extensible points in the Bean's life cycle in the spring container, which will be analyzed one by one

3.ApplicationContextInitializer

org.springframework.context.ApplicationContextInitializer

This is the callback interface that initializes ConfigurableApplicationContext before the entire spring container is refreshed. In simple terms, it calls the initialize method before the container is refreshed. This point can be extended by users themselves. Users can do something before the entire spring container is initialized.

The conceivable scenario may be to activate some configurations at the beginning, or use the time when the class has not been loaded by the class loader to perform operations such as dynamic bytecode injection.

The extension method is:

public class TestApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("[ApplicationContextInitializer]");
    }
}

Because the spring container has not been initialized at this time, there are three ways to make your extension effective:

  • Use the springApplication.addInitializers(new TestApplicationContextInitializer()) statement in the startup class to add

  • Configuration file configuration context.initializer.classes=com.example.demo.TestApplicationContextInitializer

  • Spring SPI extension, add org.springframework.context.ApplicationContextInitializer=com.example.demo.TestApplicationContextInitializer in spring.factories

4.BeanDefinitionRegistryPostProcessor

org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

This interface is executed after reading the beanDefinition in the project and provides a supplementary extension point

Usage scenario: you can dynamically register your own beanDefinition here and load beans other than classpath

The extension method is:

public class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("[BeanDefinitionRegistryPostProcessor] postProcessBeanDefinitionRegistry");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("[BeanDefinitionRegistryPostProcessor] postProcessBeanFactory");
    }
}

5.BeanFactoryPostProcessor

org.springframework.beans.factory.config.BeanFactoryPostProcessor

This interface is the extension interface of beanFactory. The calling time is after spring reads beanDefinition information and before instantiating beans.

At this time, users can handle some things by themselves by implementing the extension interface, such as modifying the meta information of the registered beanDefinition.

The extension method is:

public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("[BeanFactoryPostProcessor]");
    }
}

6.InstantiationAwareBeanPostProcessor

org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor

This interface inherits the BeanPostProcess interface, with the following differences:

The BeanPostProcess interface only extends in the bean initialization phase (before and after injecting the spring context), while the instantiaawarebeanpostprocessor interface adds three methods on this basis, adding the extensible scope to the instantiation phase and attribute injection phase.

The main extension points of this class include the following five methods, which are mainly in the two major stages of the bean life cycle: instantiation stage and initialization stage. They are described below in the order of call:

  • Postprocessbeforeinstance: before instantiating the bean, it is equivalent to before new

  • Postprocessafterinstance: after instantiating the bean, it is equivalent to after new

  • postProcessPropertyValues: the bean has been instantiated and triggered at the stage of property injection. Annotation principles such as @ Autowired and @ resource are implemented based on this method

  • postProcessBeforeInitialization: before initializing the bean, it is equivalent to before injecting the bean into the spring context

  • postProcessAfterInitialization: after initializing the bean, it is equivalent to injecting the bean into the spring context

Usage scenario: this extension point is very useful. It can be used in middleware and business. For example, collect beans that implement a certain type of interface in each life period, or set unified values for beans of a certain type, and so on.

The extension method is:

public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("[TestInstantiationAwareBeanPostProcessor] before initialization " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("[TestInstantiationAwareBeanPostProcessor] after initialization " + beanName);
        return bean;
    }

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("[TestInstantiationAwareBeanPostProcessor] before instantiation " + beanName);
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("[TestInstantiationAwareBeanPostProcessor] after instantiation " + beanName);
        return true;
    }

    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
        System.out.println("[TestInstantiationAwareBeanPostProcessor] postProcessPropertyValues " + beanName);
        return pvs;
    }

7.SmartInstantiationAwareBeanPostProcessor

org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor

The extension interface has three trigger point methods:

  • predictBeanType: this trigger point occurs before postprocessbeforeinstance (it is not indicated in the figure, because it is generally unnecessary to extend this point). This method is used to predict the type of bean and return the first Class type successfully predicted. If it cannot be predicted, it returns null; When you call BeanFactory.getType(name), when the bean type information cannot be obtained through the bean name, you call the callback method to determine the type information.

  • determineCandidateConstructors: this trigger point occurs after postprocessbeforeinstance. It is used to determine the constructor of the bean. It returns a list of all constructors of the bean. Users can extend this point to customize and select the corresponding constructor to instantiate the bean.

  • getEarlyBeanReference: this trigger point occurs after postProcessAfterInstantiation. When there is a cyclic dependency scenario, after the bean is instantiated, in order to prevent cyclic dependency, the callback method will be exposed in advance for post-processing of bean instantiation. This method is triggered in the callback method exposed in advance.

The extension method is:

public class TestSmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {

    @Override
    public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] predictBeanType " + beanName);
        return beanClass;
    }

    @Override
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] determineCandidateConstructors " + beanName);
        return null;
    }

    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] getEarlyBeanReference " + beanName);
        return bean;
    }
}

8.BeanFactoryAware

org.springframework.beans.factory.BeanFactoryAware

This class has only one trigger point, which occurs after bean instantiation and before property injection, that is, before Setter. The extension point method of this class is setBeanFactory. You can get the BeanFactory property.

The usage scenario is that you can get the bean after instantiation but before initialization   BeanFactory, at this time, you can make special customization for each bean. Or you can take the BeanFactory to cache and use it in the future.

The extension method is:

public class TestBeanFactoryAware implements BeanFactoryAware {
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("[TestBeanFactoryAware] " + beanFactory.getBean(TestBeanFactoryAware.class).getClass().getSimpleName());
    }
}

9.ApplicationContextAwareProcessor

org.springframework.context.support.ApplicationContextAwareProcessor

The class itself has no extension points, but there are six extension points inside the class for implementation. The trigger time of these classes is after bean instantiation and before initialization

It can be seen that this class is used to execute various driver interfaces. After bean instantiation and attribute filling, the variables of the corresponding container can be obtained by executing the extension interface marked in the red box above. So there should be six extension points here. Let's put them together

  • EnvironmentAware: an extension class used to obtain EnvironmentAware. This variable is very useful and can obtain all parameters in the system. Of course, I don't think this Aware needs to be extended, because spring can be directly obtained through injection.

  • Embeddedvalueresolveaware: an extension class used to obtain StringValueResolver,   StringValueResolver is used to obtain variables based on properties of String type. Generally, we use @ Value to obtain them. If we implement the Aware interface, cache the StringValueResolver and obtain variables of String type through this class, the effect is the same.

  • ResourceLoaderAware: an extension class used to obtain ResourceLoader. ResourceLoader can be used to obtain all resource objects in the classpath. This class can be extended to obtain ResourceLoader objects.

  • ApplicationEventPublisherAware: an extension class used to obtain ApplicationEventPublisher. ApplicationEventPublisher can be used to publish events and used together with ApplicationListener. It will be mentioned in detail when introducing ApplicationListener below. This object can also be obtained by spring injection.

  • MessageSourceAware: an extension class used to obtain MessageSource, which is mainly used for internationalization.

  • ApplicationContextAware: an extension class used to obtain ApplicationContext. ApplicationContext should be a very familiar class to many people. It is the spring context manager. It can manually obtain any bean registered in the spring context. We often extend this interface to cache the spring context and wrap it into static methods. Meanwhile, ApplicationContext also implements BeanFactory, MessageSource, ApplicationEventPublisher and other interfaces, which can also be used to do related interface things.

10.BeanNameAware

org.springframework.beans.factory.BeanNameAware

You can see that this class is also a kind of Aware extension. The trigger point is before bean initialization, that is, before postProcessBeforeInitialization. There is only one trigger point method of this class: setBeanName

The usage scenario is: the user can extend this point, get the beanName registered in the spring container before initializing the bean, and modify the value of the beanName from the line.

The extension method is:

public class NormalBeanA implements BeanNameAware{
    public NormalBeanA() {
        System.out.println("NormalBean constructor");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("[BeanNameAware] " + name);
    }
}

11.@PostConstruct

javax.annotation.PostConstruct

This is not an extension point, but a label. Its function is to call a method first if @ PostConstruct is marked on it during bean initialization. The focus here is to pay attention to the standard trigger point, which is after postProcessBeforeInitialization and before initializingbean.afterpropertieset.

Usage scenario: you can label a method to initialize an attribute

The extension method is:

public class NormalBeanA {
    public NormalBeanA() {
        System.out.println("NormalBean constructor");
    }

    @PostConstruct
    public void init(){
        System.out.println("[PostConstruct] NormalBeanA");
    }
}

12.InitializingBean

org.springframework.beans.factory.InitializingBean

This class, as the name suggests, is also used to initialize beans. The InitializingBean interface provides a way for beans to initialize methods. It only includes the afterpropertieset method. All classes that inherit this interface will execute this method when initializing beans. The trigger time of this extension point is before postProcessAfterInitialization.

Usage scenario: the user implements this interface to initialize some business indicators during system startup.

The extension method is:

public class NormalBeanA implements InitializingBean{
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("[InitializingBean] NormalBeanA");
    }
}

13.FactoryBean

org.springframework.beans.factory.FactoryBean

In general, spring uses the class attribute of the bean to specify branch classes to instantiate the bean through the reflection mechanism. In some cases, the process of instantiating the bean is complex. If you follow the traditional method, you need to provide a lot of configuration information in the bean. The flexibility of configuration mode is limited. At this time, a simple scheme may be obtained by coding. Spring provides a factory class interface of org.springframework.bean.factory.FactoryBean for this purpose. Users can customize the logic of instantiating beans by implementing this interface. FactoryBean interface occupies an important position for spring framework. Spring itself provides the implementation of more than 70 factorybeans. They hide the details of instantiating some complex beans and bring convenience to the upper application. Starting from spring 3.0, FactoryBean began to support generics, that is, the interface declaration was changed to FactoryBean < T >

Usage scenario: users can extend this class to act as a proxy for the bean to be instantiated, such as intercepting all methods of the object, outputting a line of log before and after the call, imitating the function of ProxyFactoryBean.

The extension method is:

public class TestFactoryBean implements FactoryBean<TestFactoryBean.TestFactoryInnerBean> {

    @Override
    public TestFactoryBean.TestFactoryInnerBean getObject() throws Exception {
        System.out.println("[FactoryBean] getObject");
        return new TestFactoryBean.TestFactoryInnerBean();
    }

    @Override
    public Class<?> getObjectType() {
        return TestFactoryBean.TestFactoryInnerBean.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public static class TestFactoryInnerBean{

    }
}

14.SmartInitializingSingleton

org.springframework.beans.factory.SmartInitializingSingleton

There is only one method afterSingletonsInstantiated in this interface, whose function is to call the callback interface after the initialization of all singleton objects (non lazy objects) that are managed by spring container. The trigger time is after postProcessAfterInitialization.

Usage scenario: users can extend this interface to perform some post-processing after initializing all singleton objects.

The extension method is:

public class TestSmartInitializingSingleton implements SmartInitializingSingleton {
    @Override
    public void afterSingletonsInstantiated() {
        System.out.println("[TestSmartInitializingSingleton]");
    }
}

15.CommandLineRunner

org.springframework.boot.CommandLineRunner

This interface also has only one method: run(String... args). The trigger time is automatically executed after the whole project is started. If there are multiple commandlinerunners, you can use @ Order to sort.

Usage scenario: the user extends this interface to preprocess some businesses after starting the project.

The extension method is:

public class TestCommandLineRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("[TestCommandLineRunner]");
    }
}

16.DisposableBean

org.springframework.beans.factory.DisposableBean

This extension point also has only one method: destroy(), which is triggered when the object is destroyed. This method will be executed automatically. For example, this method will be triggered when applicationContext.registerShutdownHook is run.

The extension method is:

public class NormalBeanA implements DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("[DisposableBean] NormalBeanA");
    }
}

17.ApplicationListener

org.springframework.context.ApplicationListener

To be exact, this should not be an extension point in spring & springboot. ApplicationListener can listen to the event of an event, and the trigger time can be interspersed during the execution of business methods. Users can customize a business event. However, spring also has some built-in events, which can be interspersed in the startup call. We can also use this feature to do some built-in event listeners to achieve roughly the same things as the previous trigger points.

Next, list the main spring built-in events:

  • ContextRefreshedEvent

    This event is published when the ApplicationContext is initialized or refreshed. This can also be used in the ConfigurableApplicationContext interface   refresh() method. Initialization here means that all beans are successfully loaded, post-processing beans are detected and activated, all singleton beans are pre instantiated, and the ApplicationContext container is ready and available.
     

  • ContextStartedEvent

    When used   ConfigurableApplicationContext   (ApplicationContext sub interface) the start() method in the interface starts   The event is published when ApplicationContext. You can investigate your database, or you can restart any stopped application after receiving this event.
     

  • ContextStoppedEvent

    When used   In the ConfigurableApplicationContext interface   stop() stop ApplicationContext   Publish this event when. You can do the necessary cleaning up after receiving this event
     

  • ContextClosedEvent

    When used   In the ConfigurableApplicationContext interface   The close() method closes   ApplicationContext   This event is published when. A closed context reaches the end of the life cycle; It cannot be refreshed or restarted
     

  • RequestHandledEvent

    This is a Web specific event that tells all beans that HTTP requests have been serviced. Can only be applied to Web applications that use DispatcherServlet. When Spring is used as the front-end MVC controller, the system will automatically trigger this event when Spring finishes processing user requests
     

18. Finally

From these spring & springboot extension points, we can roughly see the whole bean life cycle. When developing business or writing middleware business, we can make rational use of the extension points provided by spring to do something in each stage of spring startup. To achieve the purpose of custom initialization.

Posted by oceans on Tue, 09 Nov 2021 00:19:23 -0800