Springboot boot boot extension

  • 1. Background
  • 2. Extensible interface startup call sequence diagram
  • 3.ApplicationContextInitializer
  • 4.BeanDefinitionRegistryPostProcessor
  • 5.BeanFactoryPostProcessor
  • 6.InstantiationAwareBeanPostProcessor
  • 7.SmartInstantiationAwareBeanPostProcessor
  • 8.BeanFactoryAware
  • 9.ApplicationContextAwareProcessor
  • 10.BeanNameAware
  • 11.@PostConstruct
  • 12.InitializingBean
  • 13.FactoryBean
  • 14.SmartInitializingSingleton
  • 15.CommandLineRunner
  • 16.DisposableBean
  • 17.ApplicationListener
  • 18. Finally



1. Background

The core idea of Spring is the container. When the container refresh es, the outside looks calm, but in fact, the inside is a rough sea. Springboot encapsulates Spring, which follows the Convention rather than configuration, plus the mechanism of automatic assembly. Many times, we can complete the assembly of a function as long as we reference a dependency, which is almost zero configuration.

I like this automatic assembly mechanism very much, so I will also use this feature when developing middleware and public dependency tools myself. Let users access at the least cost. If you want to play with automatic assembly, you must understand the construction life cycle of spring for beans and various extension interfaces. Of course, understanding the various life cycles of beans can also help us deepen our understanding of spring. Business code can also make rational use of these extension points to write more beautiful code.

Search for spring extension points on the Internet and find that few blog posts say everything, only some descriptions of common extension points.

So in this article, I summarized almost all the extension interfaces of Spring & springboot and 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 for the entire spring container to initialize the ConfigurableApplicationContext before refreshing. In short, it is to call the initialize method of this class before refreshing the container. 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 carry out dynamic bytecode injection and other operations.

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:

  • In the startup class, use springapplication Add initializers (New testapplicationcontextinitializer()) statement
  • Configuration file configuration context initializer. classes=com. example. demo. TestApplicationContextInitializer
  • Spring SPI extension, in spring Add org. To factories springframework. context. ApplicationContextInitializer=com. example. demo. TestApplicationContextInitializer

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 this 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 initialization phase of the bean (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 bean
  • 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 a unified value for a certain type of beans, 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: the 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 with successful prediction. If it cannot be predicted, return null; When you call beanfactory GetType (name): when the bean type information cannot be obtained through the bean name, the callback method is called 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, and you can get the property BeanFactory.

The usage scenario is that you can get the BeanFactory after the bean is instantiated but before initialization. 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.
  • Embeddedvalueresolver Aware: 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 this Aware interface is implemented, 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, which 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

It can be seen 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 initializing bean after postProcessBeforeInitialization Before afterpropertiesset.

Usage scenario: users 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 the branch class to instantiate the bean through the reflection mechanism. In some cases, the process of instantiating the bean is relatively complex. If you follow the traditional way, 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 an org. Org for this purpose springframework. bean. factory. The factory class interface of FactoryBean. Users can customize the logic of instantiating bean 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. From spring 3 Starting from 0, FactoryBean began to support generics, that is, the interface declaration was changed to the form of 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

In this interface, there is only one method, afterSingletonsInstantiated, which is used to call the callback interface after the initialization of all singleton objects (non lazy load objects) managed by the spring container. The trigger time is after postProcessAfterInitialization.

Usage scenario: users can extend this interface to do some post business 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, run ApplicationContext This method is triggered when registershutdownhook.

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, the trigger time can be interspersed in the execution process of business methods, and 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 happen using the refresh() method in the ConfigurableApplicationContext interface. Singleton refers to all containers that have been instantiated successfully and are available after being initialized. Singleton refers to all containers that have been instantiated and activated.

  • ContextStartedEvent

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

  • ContextStoppedEvent

    This event is published when the ApplicationContext is stopped using stop() in the ConfigurableApplicationContext interface. You can do the necessary cleaning up after receiving this event

  • ContextClosedEvent

    This event is published when the ApplicationContext is closed using the close() method in the ConfigurableApplicationContext interface. 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 using DispatcherServlet. When Spring is used as the front-end MVC controller, the system will automatically trigger this event when Spring finishes processing user requests

Tags: Spring Boot

Posted by BuzFortuna on Tue, 10 May 2022 05:53:27 +0300