Do you know the startup extension points of Spring Boot?

1.Background

The core idea of ​​Spring is the container. When the container refreshes, the outside looks calm, but inside it is a stormy sea and a vast ocean. Springboot encapsulates Spring, follows convention rather than configuration, and adds an automatic assembly mechanism. Many times, as long as we reference a dependency, we can complete the assembly of a function with almost zero configuration.

I like this automatic assembly mechanism very much, so I also use this feature when developing middleware and public dependency tools. Allow users to access with minimal cost. If you want to play with automatic assembly, you must understand spring's bean construction life cycle 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 reasonable use of these extension points to write more beautiful code.

Searching for spring extension points on the Internet, I found that there are few blog posts that are comprehensive, only some explanations of commonly used extension points.

So 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 a sequential call diagram of a bean from being loaded to final initialization in spring to complete all extensibility points. Thus we can also peek into how beans are loaded into the spring container step by step.

2. Extensible interface startup calling sequence diagram

The following is the calling sequence of all extensible points in the Bean life cycle in the spring container that I have organized. I will analyze them one by one below.

picture

3.ApplicationContextInitializer

org.springframework.context.ApplicationContextInitializer

ConfigurableApplicationContextThis is the callback interface that the entire spring container is initialized before refreshing . Simply put, this initializemethod is called before the container is refreshed. This point allows for extension by the user. Users can do something before the entire spring container has been initialized.

The conceivable scenarios may be to activate some configurations at the beginning, or to use the opportunity 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 own extensions effective:

  • springApplication.addInitializers(new TestApplicationContextInitializer())Use the statement in the startup class to add
  • Profile configurationcontext.initializer.classes=com.example.demo.TestApplicationContextInitializer
  • Spring SPI extension, added in spring.factoriesorg.springframework.context.ApplicationContextInitializer=com.example.demo.TestApplicationContextInitializer

4.BeanDefinitionRegistryPostProcessor

org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

This interface is executed after reading the project beanDefinition, providing a supplementary extension point

Usage scenarios: You can dynamically register your own here beanDefinitionand load beans outside the 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 beanFactoryan extended interface, and the calling time is after spring reads beanDefinitionthe information and before instantiating the bean.

At this time, users can handle some things by themselves by implementing this extended interface, such as modifying registered beanDefinitionmeta information.

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 BeanPostProcessthe interface, the differences are as follows:

BeanPostProcessThe interface is only expanded during the initialization phase of the bean (before and after the spring context is injected), and InstantiationAwareBeanPostProcessorthe interface adds 3 methods on this basis, adding the extensible scope to the instantiation phase and attribute injection phase.

The main extension points of this class have the following five methods, which are mainly in the two major stages of the bean life cycle: the instantiation stage  and the initialization stage  . They are explained together below, and the calling order is:

  • postProcessBeforeInstantiation: Before instantiating the bean, it is equivalent to before the new bean.
  • postProcessAfterInstantiation: After instantiating the bean, it is equivalent to after the new bean.
  • postProcessPropertyValues: The bean has been instantiated and is triggered during attribute injection. Annotation principles such as @Autowired, @Resourceetc. 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 scenarios: This extension point is very useful. You can take advantage of this feature whether you are writing middleware or in business. For example, beans that implement a certain type of interface are collected during each life cycle, or beans of a certain type are set uniformly, etc.

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

This extension interface has 3 trigger point methods:

  • predictBeanType: This trigger point occurred before postProcessBeforeInstantiation(it is not marked on the figure because it is generally not necessary to expand this point). This method is used to predict the type of Bean and return the first Class type that is 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, the callback method is called to determine the type information.
  • determineCandidateConstructors: This trigger point occurs postProcessBeforeInstantiationlater and is used to determine the constructor of the bean. What is returned is a list of all constructors of the bean. The user can extend this point to customize the selection of the corresponding constructor to instantiate the bean.
  • getEarlyBeanReference: This trigger point occurs later postProcessAfterInstantiation, when there is a cyclic dependency scenario, and after the bean is instantiated, in order to prevent cyclic dependencies, the callback method will be exposed in advance for post-processing of the 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 the bean is instantiated and before the properties are injected, that is, before the Setter. The extension point method of this class is setBeanFactory, you can get BeanFactorythis attribute.

The usage scenario is that you can get it after the bean is instantiated but before it is initialized.  BeanFactoryAt this time, you can make special customizations for each bean. Or you can BeanFactorycache it and use it later.

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 6 extension points within the class that can be implemented. These classes are triggered after the bean is instantiated and before initialization.

2.png

It can be seen that this class is used to execute various driver interfaces. After the bean is instantiated and the attributes are filled, the variables of the corresponding container are obtained by executing the extended interface marked by the red box above. So there should be 6 extension points here  . Let’s talk about them together here.

  • EnvironmentAware: EnviromentAwareAn extension class used to obtain. This variable is very useful and can obtain all parameters in the system. Of course, I personally think that there is no need to extend this Aware, because it can be obtained directly through injection inside spring.
  • EmbeddedValueResolverAware: StringValueResolverAn extension class  StringValueResolverused to obtain variables based on Stringtype properties. Generally, we use @Valuethe method to obtain them. If this Aware interface is implemented, cache it StringValueResolverand obtain Stringtype variables through this class. The effect is the same.
  • ResourceLoaderAware: ResourceLoaderAn extension class used to obtain, ResourceLoaderwhich can be used to obtain all resource objects in the classpath. This class can be extended to obtain the ResourceLoaderobjects.
  • ApplicationEventPublisherAware: ApplicationEventPublisherAn extension class used for acquisition, ApplicationEventPublisherwhich can be used to publish events and be ApplicationListenerused together. It ApplicationListenerwill be mentioned in detail in the introduction below. This object can also be obtained through spring injection.
  • MessageSourceAware: MessageSourceAn extension class used for acquisition, MessageSourcemainly used for internationalization.
  • ApplicationContextAwareApplicationContext: An extension class used to obtain ApplicationContext, which should be a class that many people are very familiar with, is the spring context manager. You can manually obtain any beans registered in the spring context. We often extend this interface to cache the spring context and package it as static methods. At the same time , ApplicationContextit also implements interfaces such as , and can also be used to do related interface things.BeanFactoryMessageSourceApplicationEventPublisher

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 the initialization of the bean. That is, postProcessBeforeInitializationbefore, there is only one trigger point method of this class:setBeanName

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

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, it is actually an annotation. Its function is during the initialization phase of the bean. If a method is marked @PostConstruct, this method will be called first. The key point here is to pay attention to the trigger point of this standard. This trigger point is postProcessBeforeInitializationafter and InitializingBean.afterPropertiesSetbefore.

Usage scenario: Users can annotate a method to initialize a certain 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. InitializingBeanThe interface provides a way to initialize the bean. It only includes afterPropertiesSetmethods. Any class that inherits the interface will execute this method when initializing the bean. The triggering time of this extension point is postProcessAfterInitializationbefore.

Usage scenario: Users implement this interface to initialize some business indicators when the system starts.

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

Under normal circumstances, Spring uses the bean's class attribute to specify the branch class to instantiate the bean through the reflection mechanism. In some cases, the process of instantiating the bean is more complicated. If you follow the traditional method, you need to provide a large amount of configuration information in the bean. . The flexibility of the configuration method is limited. In this case, a simple solution may be obtained by coding. Spring provides a org.springframework.bean.factory.FactoryBeanfactory class interface for this purpose, and users can customize the logic of instantiated beans by implementing this interface. FactoryBeanInterfaces occupy an important position in the Spring framework, and Spring itself provides more than 70 FactoryBeanimplementations. They hide the details of instantiating some complex beans and bring convenience to upper-layer applications. Starting from Spring 3.0, FactoryBeangenerics are supported, that is, the interface declaration is changed FactoryBean<T>to

Usage scenario: Users can extend this class to act as a proxy for the bean to be instantiated, such as making an interceptor for all methods of the object and outputting a line of log before and after the call, imitating the function 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 in this interface afterSingletonsInstantiated, which is a callback interface called after the initialization of all singleton objects (non-lazy-loaded objects) managed by the spring container. Its triggering time is postProcessAfterInitializationlater.

Usage scenarios: Users can extend this interface to do some post-processing 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 triggering time is automatically executed after the entire project is started. If there are multiple CommandLineRunner, you can use them @Orderto sort them.

Usage scenario: Users extend this interface to perform preprocessing of some services 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(), and its triggering time is when this object is destroyed, this method will be automatically executed. For example applicationContext.registerShutdownHook, this method will be triggered when running.

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 precise, this should not be considered an extension point in spring&springboot. ApplicationListenerIt can monitor a certain event event. The triggering time can be interspersed during the execution of the business method, and the user can customize a certain business event. But spring also has some built-in events, which can be interspersed in startup calls. We can also use this feature to make some built-in event listeners ourselves to achieve roughly the same thing as the previous trigger points.

Next, we list the main built-in events of spring:

  • ContextRefreshedEvent

    This event is posted when the ApplicationContext is initialized or refreshed. This can also happen ConfigurableApplicationContextusing methods in interfaces  . refresh()Initialization here means: all beans are successfully loaded, post-processing beans are detected and activated, all Singleton beans are pre-instantiated, and the ApplicationContextcontainer is ready for use.

  • ContextStartedEvent

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

  • ContextStoppedEvent

    This event is published when using  stop ConfigurableApplicationContextin the interface   . You can do the necessary cleanup work after receiving this eventstop()ApplicationContext

  • ContextClosedEvent

     This event is published when closed using  methods  ConfigurableApplicationContextin the interface  . A closed context has reached the end of its life cycle; it cannot be refreshed or restartedclose()ApplicationContext

  • RequestHandledEvent

    This is a web-specific event that tells all beans that HTTP requests have been served. Can only be applied to web applications using DispatcherServlet. When using Spring as the front-end MVC controller, the system will automatically trigger this event after Spring finishes processing the user request.

18.Finally

From these spring&springboot extension points, we can roughly have a glimpse of the entire bean life cycle. When developing business or writing middleware business, we can make reasonable use of the extension points provided by spring to do something in each stage of spring startup. To achieve the purpose of custom initialization. In this summary, if there are any errors or omissions, please correct me.

Guess you like

Origin blog.csdn.net/2301_76607156/article/details/130526090