Springboot boot boot extension point super detailed summary, no longer afraid of the interviewer asked

Time:2021-6-6

1. Background

The core idea of spring is the container. When the container refreshes, it looks calm on the outside, but in fact, it’s rough and stormy on the inside. Springboot encapsulates spring, follows the convention more than configuration, plus the mechanism of automatic assembly. Most of the time, we only need to refer to a dependency, almost zero configuration, to complete the assembly of a function.

I like this automatic assembly mechanism very much, so I will also use this feature when I develop middleware and public dependency tools. Let users access at the minimum cost. If you want to make automatic assembly work, 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 reasonably use these extension points to write more beautiful code.

In the online search spring extension point, found that few blog said very complete, only some commonly used extension point description.

So in this article, I summarize almost all the extension interfaces of Spring & springboot, as well as the usage scenarios of each extension point. And sorted out a bean in spring from being loaded to the final initialization to complete all extensible point sequence call diagram. So we can see how beans are loaded into the spring container step by step.

2. Extensible interface start call sequence diagram

The following is the call order of all extensible points in the bean life cycle in the spring container I sorted out, which will be analyzed one by one

Springboot boot boot extension point super detailed summary, no longer afraid of the interviewer asked

3.ApplicationContextInitializer

org.springframework.context.ApplicationContextInitializer

This is the entire spring container initialized before refreshingConfigurableApplicationContextThe callback interface, in short, is called before the container is refreshed.initializemethod. This point allows users to expand themselves. Users can do something before the entire spring container is initialized.

The scenario you can think of might 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 dynamic bytecode injection and other operations.

The expansion mode is as follows:

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 its own extension effective:

  • Use thespringApplication.addInitializers(new TestApplicationContextInitializer())Statement addition
  • Profile configurationcontext.initializer.classes=com.example.demo.TestApplicationContextInitializer
  • Spring SPI extension, add in spring.factorsorg.springframework.context.ApplicationContextInitializer=com.example.demo.TestApplicationContextInitializer

4.BeanDefinitionRegistryPostProcessor

org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

This interface is used to read thebeanDefinitionAfter that, a supplementary extension point is provided

Usage scenario: you can dynamically register your ownbeanDefinitionTo load beans other than classpath

The expansion mode is as follows:

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 isbeanFactoryThe time to call is spring and the time to read is springbeanDefinitionAfter the information, before instantiating the bean.

At this time, users can implement the extension interface to handle some things by themselves, such as modifying the registered interfacebeanDefinitionMeta information of.

The expansion mode is as follows:

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

The interface inherits theBeanPostProcessThe differences are as follows:

<font color=”red”>BeanPostProcessThe interface is only extended in the initialization phase of the bean (before and after injection of the spring context), not theInstantiationAwareBeanPostProcessorBased on the interface, three methods are added to increase the extensible scope to the instantiation stage and the attribute injection stage.</font>

The main extension points of this class include the following five methods, which are mainly in the two stages of bean life cycle: < font color = Red >Instantiation phase< / font > and < font color = Red >Initialization phase< / font >, which are described in the following order:

  • postProcessBeforeInstantiation: before instantiating a bean, it is equivalent to before the bean new
  • postProcessAfterInstantiation: after instantiating the bean, it is equivalent to the bean new
  • postProcessPropertyValues: the bean has been instantiated and triggered in the property injection phase,@Autowired,@ResourceThe principle of equal annotation is 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 both middleware and business. For example, the collection of beans that implement a certain type of interface in each lifetime, or the uniform setting value of a certain type of beans, etc.

The expansion mode is as follows:

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

There are three trigger point methods for the extension interface

  • predictBeanType: the trigger occurs atpostProcessBeforeInstantiationBefore (it is not indicated in the figure, because it is not necessary to extend this point), this method is used to predict the type of bean, and returns the first successful class type. If it cannot be predicted, it returns null; When you callBeanFactory.getType(name)When the bean type information cannot be obtained by the name of the bean, the callback method is called to determine the type information.
  • determineCandidateConstructors: the trigger occurs atpostProcessBeforeInstantiationAfter that, it is used to determine the constructor of the bean, and the list of all constructors of the bean is returned. Users can extend this point and select the appropriate constructor to instantiate the bean.
  • getEarlyBeanReference: the trigger occurs atpostProcessAfterInstantiationAfter that, when there is a cyclic dependency scenario and 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 early exposed callback method.

The expansion mode is as follows:

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 property is injected, that is, before setter. The extension point method of this class issetBeanFactoryYou can get itBeanFactoryThis property.

The usage scenario is that you can get theBeanFactoryAt this time, you can customize each bean specifically. Or you can putBeanFactoryGet it for caching and use it later.

The expansion mode is as follows:

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 to implement inside the class. These classes are triggered after bean instantiation and before initialization

Springboot boot boot extension point super detailed summary, no longer afraid of the interviewer asked

As you can see, 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 can be obtained by executing the extension interface marked in the red box above.So there are six extension pointsLet’s put it together

  • EnvironmentAware: for gettingEnviromentAwareThis variable is very useful, you can get all the parameters in the system. Of course, I don’t think it’s necessary to extend the aware, because spring can be directly obtained by injection.
  • EmbeddedValueResolverAware: for gettingStringValueResolverAn extension class of,StringValueResolverUsed to get theStringWe usually use the properties variable of type@ValueIf the aware interface is implemented, theStringValueResolverCache it and get it through this classStringType of variable, the effect is the same.
  • ResourceLoaderAware: for gettingResourceLoaderAn extension class of,ResourceLoaderIt can be used to get all the resource objects in the classpath. You can extend this class to get themResourceLoaderObject.
  • ApplicationEventPublisherAware: for gettingApplicationEventPublisherAn extension class of,ApplicationEventPublisherCan be used to publish events, combined withApplicationListenerTo use together, as described belowApplicationListenerIt will be mentioned in detail. This object can also be obtained by spring injection.
  • MessageSourceAware: for gettingMessageSourceAn extension class of,MessageSourceIt is mainly used for internationalization.
  • ApplicationContextAware: used to getApplicationContextAn extension class of,ApplicationContextSpring context manager is a class that many people are very familiar with. It can manually obtain any bean registered in the spring context. We often extend this interface to cache the spring context and wrap it as a static method. meanwhileApplicationContextIt has also been realizedBeanFactoryMessageSourceApplicationEventPublisherAnd other interfaces can also be used to do things related to interfaces.

10.BeanNameAware

org.springframework.beans.factory.BeanNameAware

As you can see, this class is also a kind of aware extension. The trigger point is before the initialization of the bean, that ispostProcessBeforeInitializationPreviously, there was only one trigger method for 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 from the row.

The expansion mode is as follows:

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

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

[email protected]

javax.annotation.PostConstruct

This is not an extension point, but a annotation. Its function is to mark a method in the initialization phase of bean@PostConstruct, will call this method first. The key point here is to pay attention to the trigger point of this standard, which is in thepostProcessBeforeInitializationAfter that,InitializingBean.afterPropertiesSetBefore.

Usage scenario: users can annotate a method to initialize an attribute

The expansion mode is as follows:

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.InitializingBeanInterface provides a way for beans to initialize methods, which only includeafterPropertiesSetMethod. Any class that inherits the interface will execute the method when initializing the bean. What is the trigger time of this extension pointpostProcessAfterInitializationBefore.

Usage scenario: users implement this interface to initialize some business indicators during system startup.

The expansion mode is as follows:

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 reflection mechanism to specify the branch class of bean by using the class attribute of bean to instantiate bean. In some cases, the process of instantiating bean is complex. If we follow the traditional way, we need to provide a lot of configuration information in bean. The flexibility of configuration mode is limited, so a simple scheme may be obtained by using coding mode. Spring provides a platform for thisorg.springframework.bean.factory.FactoryBeanThe user can customize the logic of instantiating bean by implementing the factory class interface of.FactoryBeanInterfaces play an important role in spring framework. Spring itself provides more than 70 interfacesFactoryBeanThe implementation of the. They hide the details of instantiating some complex beans and bring convenience to the upper application. Starting with spring 3.0,FactoryBeanStart to support generics, that is, change the interface declaration toFactoryBean<T>The form of

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

The expansion mode is as follows:

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 interfaceafterSingletonsInstantiatedIts function is to call the callback interface after the initialization of all singleton objects (non lazy objects) that are managed by the spring container. The trigger time ispostProcessAfterInitializationAfter that.

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

The expansion mode is as follows:

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

15.CommandLineRunner

org.springframework.boot.CommandLineRunner

This interface has only one method:run(String... args)The trigger time is automatically executed after the whole project is started. If there are more than oneCommandLineRunner, which can be used@OrderTo sort.

Usage scenario: users extend this interface to preprocess some services after starting the project.

The expansion mode is as follows:

public class TestCommandLineRunner implements CommandLineRunner {

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

16.DisposableBean

org.springframework.beans.factory.DisposableBean

There is only one method for this extension point:destroy()When the object is destroyed, this method will be automatically executed. Like runningapplicationContext.registerShutdownHookThis method is triggered.

The expansion mode is as follows:

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 of Spring & springboot,ApplicationListenerCan listen for an eventeventThe trigger time can be interspersed in the process of business method execution, and users can customize a business event. But spring also has some built-in events, which can be interspersed in the startup call. We can also use this feature to make our own built-in event listeners to achieve something similar to the previous trigger points.

Next, list the main built-in events of spring

  • ContextRefreshedEvent

    This event is published when the ApplicationContext is initialized or refreshed. This can also be done in the ConfigurableApplicationContextInterfacerefresh() Methods. Initialization here means that all beans are loaded successfully, post-processing beans are detected and activated, and all singleton beans are pre instantiated,ApplicationContextThe container is ready for use.

  • ContextStartedEvent

    When usingConfigurableApplicationContextStart() method in (ApplicationContext sub interface) interfaceApplicationContext The event is published. You can investigate your database, or you can restart any stopped application after receiving this event.

  • ContextStoppedEvent

    When usingConfigurableApplicationContext In the interfacestop() stop it ApplicationContextThis event is published when the. You can do the necessary cleaning after you receive the incident

  • ContextClosedEvent

    When usingConfigurableApplicationContextIn the interfaceclose()Method closeApplicationContextThe event is published. A closed context reaches the end of the lifecycle; It cannot be refreshed or restarted

  • RequestHandledEvent

    This is a web specific event that tells all beans that the HTTP request has been served. It can only be applied to web applications that use the dispatcher servlet. When spring is used as the front-end MVC controller, the system will automatically trigger this event when spring finishes processing user requests

18. Final

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 reasonable use of the extension points provided by spring, and do something in each stage of spring startup. To achieve the purpose of custom initialization. If there are any mistakes or omissions in this summary, please correct them.

Next, at the request of a small partner, we are going to summarize various ways to control the loading order of beans during the startup process of springboot, so that the loading order of beans is completely under your control.

19. Contact author

Wechat focuses on getting more technical dry goods
Springboot boot boot extension point super detailed summary, no longer afraid of the interviewer asked

Recommended Today

Hot! Front and rear learning routes of GitHub target 144K

Hello, Sifu’s little friend. I’m silent Wang Er. Last week, while appreciating teacher Ruan Yifeng’s science and technology weekly, I found a powerful learning route, which has been marked with 144K on GitHub. It’s very popular. It covers not only the front-end and back-end learning routes, but also the operation and maintenance learning routes. As […]