1. The background

The core idea of Spring is that the container, when refreshed, looks calm on the outside, but inside is a sea of water. Springboot encapsulates Spring, following convention more than configuration, plus an auto-assembly mechanism. Most of the time we just reference a dependency, almost zero configuration can complete a function assembly.

I love this autowiring mechanism so much that I use it when DEVELOPING my own middleware and common dependency tools. Allow users to access with minimal cost. To get the autowiring thing going, you must understand spring’s construction lifecycle for beans and the various extension interfaces. Of course, understanding the various life cycles of beans also helps us deepen our understanding of Spring. Business code can also take advantage of these extension points to write better code.

A web search for Spring extension points turns up few blog posts that cover everything, just a few descriptions of commonly used extension points.

So in this article, I’ve summarized almost all of Spring & Springboot’s extension interfaces, as well as the usage scenarios for each extension point. It also draws up a sequential call diagram for all extensibility points of a bean within Spring from its loading to its final initialization. We can also see how the bean is loaded step by step into the Spring container.


2. Extensible interface start call sequence diagram

The following is the order of invocation of all extensible points in the life cycle of beans in the Spring container that I’ve compiled, which I’ll examine one by one


3.ApplicationContextInitializer

org.springframework.context.ApplicationContextInitializer

It is the spring container prior to refresh the initialization ConfigurableApplicationContext callback interface, in simple terms, is to call before the container to refresh the initialize method. This point can be extended by the user himself. The user can do some things before the entire Spring container is initialized.

One possible scenario is to activate some configuration initially, or to perform dynamic bytecode injection while the class is not being loaded by the class loader.

Expansion mode:

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

Since the Spring container has not yet been initialized, there are three ways to make your extension work:

  • Used in startup classesspringApplication.addInitializers(new TestApplicationContextInitializer())Statements to join
  • Configuration file 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 beanDefinition in the project, providing a supplementary extension point

Usage scenario: This is where you can dynamically register your beanDefinition and load beans outside of your classpath

Expansion mode:

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


5.BeanFactoryPostProcessor

org.springframework.beans.factory.config.BeanFactoryPostProcessor

This interface is an extension of the beanFactory interface and is called after Spring has read the beanDefinition information and before the bean is instantiated.

At this point, users can take care of things themselves by implementing the extension interface, such as modifying the meta information of registered BeanDefinitions.

Expansion mode:

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


6.InstantiationAwareBeanPostProcessor

org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor

This interface inherits the BeanPostProcess interface with the following differences:

BeanPostProcessThe interface is only extended during the bean’s initialization phase (before and after the Spring context is injected), whileInstantiationAwareBeanPostProcessorThe interface adds three methods to this, extending the scope of the instantiation phase and the property injection phase.

The main extension points of this class include the following five methods, which are mainly in the two major phases of the bean life cycle: the instantiation phase and the initialization phase, which are explained together in the following order:

  • postProcessBeforeInstantiation: before the bean is instantiated, equivalent to before the bean is new
  • postProcessAfterInstantiation: After the bean is instantiated, equivalent to after the bean is new
  • postProcessPropertyValuesThe: bean has been instantiated and is triggered in phases during property injection,@Autowired.@ResourceThe annotation principle is based on this method
  • postProcessBeforeInitialization: Before the bean is initialized, which is equivalent to before the bean is injected into the Spring context
  • postProcessAfterInitializationAfter the bean is initialized, it is the same as after the bean is injected into the Spring context

Usage scenario: This extension point is very useful for both writing middleware and business applications. Such as collecting beans that implement a particular type of interface across their lifetimes, or setting values uniformly for a particular type of bean, and so on.

Expansion mode:

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;
    }
Copy the code




7.SmartInstantiationAwareBeanPostProcessor

org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor

The extension interface has three trigger point methods:

  • predictBeanType: The trigger occurs atpostProcessBeforeInstantiationPreviously (not indicated on the diagram because it is not generally necessary to extend this point), this method was used to predict the type of the Bean, returning the first Class type of the predicted success, or null if the predicted failure; When you callBeanFactory.getType(name)The callback method is called to determine the type information when the bean type information cannot be obtained from the bean name.
  • determineCandidateConstructors: The trigger occurs atpostProcessBeforeInstantiationA list of all constructors for the bean is then returned, which is used to determine the bean’s constructors. The user can extend this point by customizing and selecting the appropriate constructor to instantiate the bean.
  • getEarlyBeanReference: The trigger occurs atpostProcessAfterInstantiationLater, when there are cyclic dependencies, when the bean is instantiated, the callback method is exposed in advance for the post-processing of the bean instantiation in order to prevent cyclic dependencies. This method is triggered in the exposed callback method.

Expansion mode:

public class TestSmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {

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

    @Override
    publicConstructor<? >[] 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);
        returnbean; }}Copy the code


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 the Setter. The extension point method for this class is setBeanFactory, which gets the BeanFactory property.

In this scenario, you can take the BeanFactory after the bean is instantiated, but before it is initialized, and at this point, you can make specific customization for each bean. Or you can cache the BeanFactory for later use.

Expansion mode:

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


9.ApplicationContextAwareProcessor

org.springframework.context.support.ApplicationContextAwareProcessor

The class itself does not have extension points, but there are six extension points that can be implemented within the class. These classes fire after the bean is instantiated but before it is initialized

As you can see, this class is used to execute the various driver interfaces to retrieve the corresponding container variables by executing the extension interfaces highlighted in the red box above after the bean is instantiated and the properties are populated. So there should be six extension points here, just put them all together

  • EnvironmentAware: Used to getEnviromentAwareThis variable is very useful to get all the parameters in the system. Of course, I don’t think it is necessary to extend Aware, because spring can be accessed directly through injection.
  • EmbeddedValueResolverAware: Used to getStringValueResolverAn extension of the class,StringValueResolverUsed to obtain based onStringA variable of type “properties” is normally used@ValueIf the Aware interface is implemented, get the Aware interfaceStringValueResolverCache it and get it through this classStringType variable, the effect is the same.
  • ResourceLoaderAware: Used to getResourceLoaderAn extension of the class,ResourceLoaderCan be used to retrieve all resource objects in the classpath, and you can extend this class to retrieve themResourceLoaderObject.
  • ApplicationEventPublisherAware: Used to getApplicationEventPublisherAn extension of the class,ApplicationEventPublisherCan be used to publish events, combineApplicationListenerTo be used together, as described belowApplicationListenerWill be discussed in detail. This object can also be obtained via Spring injection.
  • MessageSourceAware: Used to getMessageSourceAn extension of the class,MessageSourceMainly used for internationalization.
  • ApplicationContextAware: used to obtainApplicationContextAn extension of the class,ApplicationContextThe Spring Context manager can manually fetch any bean registered in the Spring context. We often extend this interface to cache the Spring context, wrapped in static methods. At the same timeApplicationContextAlso achievedBeanFactory.MessageSource.ApplicationEventPublisherAnd other interfaces can also be used to do things related to interfaces.


10.BeanNameAware

org.springframework.beans.factory.BeanNameAware

You can see, this class is also Aware an extension, trigger point before the initialization of bean, namely postProcessBeforeInitialization before this class the trigger method is only one: setBeanName

The user can extend this point to get the beanName registered in the Spring container before initializing the bean and modify the value of the beanName.

Expansion mode:

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

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


11.@PostConstruct

javax.annotation.PostConstruct

This is not an extension point, but rather a annotation. At the bean initialization stage, if a method is labeled @postconstruct, this method will be called first. Under the key here is to focus on the trigger point of this standard, the trigger point is after postProcessBeforeInitialization InitializingBean. AfterPropertiesSet before.

Usage scenario: Users can annotate a method to initialize a property

Expansion mode:

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

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


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, including only afterPropertiesSet methods, which all classes that inherit the interface execute when initializing the bean. The extension point before postProcessAfterInitialization trigger.

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

Expansion mode:

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


13.FactoryBean

org.springframework.beans.factory.FactoryBean

In general, Spring uses reflection to specify branch classes to instantiate beans using the bean’s class attribute. In some cases, the instantiation of beans is complicated and requires a lot of configuration information to be provided in the bean in the traditional way. The flexibility of configuration is limited, and coding may yield a simple solution. Spring provides a org. Springframework. Beans. Factory. FactoryBean factory class interface, users can customize by implementing the interface logic instantiation of the bean. The FactoryBean interface plays an important role in the Spring framework. Spring itself provides over 70 FactoryBean implementations. They hide the details of instantiating complex beans for the benefit of upper-layer applications. As of Spring3.0, factorybeans began to support generics, meaning that the interface declaration was changed to the form of FactoryBean

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, and output a log line before and after the call, mimicking the functionality of ProxyFactoryBean.

Expansion mode:

public class TestFactoryBean implements FactoryBean<TestFactoryBean.TestFactoryInnerBean> {

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

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

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

    public static class TestFactoryInnerBean{}}Copy the code


14.SmartInitializingSingleton

org.springframework.beans.factory.SmartInitializingSingleton

AfterSingletonsInstantiated this interface is only one method, its role is in the spring container management all the singleton object (not lazy loading) initialization is completed calls the callback interface. After the trigger is postProcessAfterInitialization.

Usage scenario: Users can extend this interface to perform some post-processing after initializing all singletons.

Expansion mode:

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


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 you have more than one CommandLineRunner, you can use @Order to sort it.

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

Expansion mode:

public class TestCommandLineRunner implements CommandLineRunner {

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


16.DisposableBean

org.springframework.beans.factory.DisposableBean

This extension point also has only one method: destroy(), which is triggered when the object is destroyed and automatically executed. Such as running applicationContext. RegisterShutdownHook, will trigger this method.

Expansion mode:

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


17.ApplicationListener

org.springframework.context.ApplicationListener

To be precise, this should not be an extension point in Spring&SpringBoot. ApplicationListener can listen for an event that can be triggered during the execution of a business method. The user can customize a business event. But Spring also has some built-in events that can be interspersed with launch calls. We can also use this feature to make our own listeners for built-in events to do much the same thing as the previous triggers.

Here’s a list of spring’s main built-in events:

  • ContextRefreshedEvent

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

  • ContextStartedEvent

    When using ConfigurableApplicationContext (ApplicationContext interface) start () method in the interface of ApplicationContext starts, the incident was released. You can investigate your database, or you can restart any stopped applications after receiving this event.

  • ContextStoppedEvent

    When using the stop ConfigurableApplicationContext interface () when they stop ApplicationContext release this event. You can do the necessary cleaning up after receiving the event

  • ContextClosedEvent

    When using ConfigurableApplicationContext close () method in the interface of closed ApplicationContext, the incident was released. A closed context reaches the end of its life cycle; It cannot be refreshed or restarted

  • RequestHandledEvent

    This is a Web-specific event that tells all beans that the HTTP request has been served. This parameter is applicable only to Web applications that use DispatcherServlet. When Spring is used as the front-end MVC controller, the system automatically fires this event when Spring finishes processing the user request


18. The last

From these spring&SpringBoot extension points, we can roughly peek into the entire bean life cycle. When developing a business or writing a middleware business, we can take advantage of the extension points spring provides and do something during the various stages of Spring startup. To achieve the purpose of custom initialization. If there are mistakes or omissions in this summary, please correct them.

In the next article, at the request of a friend, we will summarize the various ways in which we can control the loading order of beans during the SpringBoot boot process, so that you have complete control over the loading order of beans.


19. Contact the author

Focus on wechat to get more technical dry goods