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
ConfigurableApplicationContext
This is the callback interface that the entire spring container is initialized before refreshing . Simply put, this initialize
method 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 configuration
context.initializer.classes=com.example.demo.TestApplicationContextInitializer
- Spring SPI extension, added in spring.factories
org.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 beanDefinition
and 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 beanFactory
an extended interface, and the calling time is after spring reads beanDefinition
the 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 beanDefinition
meta 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 BeanPostProcess
the interface, the differences are as follows:
BeanPostProcess
The interface is only expanded during the initialization phase of the bean (before and after the spring context is injected), and InstantiationAwareBeanPostProcessor
the 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
,@Resource
etc. 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 beforepostProcessBeforeInstantiation
(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 occurspostProcessBeforeInstantiation
later 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 laterpostProcessAfterInstantiation
, 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 BeanFactory
this attribute.
The usage scenario is that you can get it after the bean is instantiated but before it is initialized. BeanFactory
At this time, you can make special customizations for each bean. Or you can BeanFactory
cache 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
:EnviromentAware
An 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
:StringValueResolver
An extension classStringValueResolver
used to obtain variables based onString
type properties. Generally, we use@Value
the method to obtain them. If this Aware interface is implemented, cache itStringValueResolver
and obtainString
type variables through this class. The effect is the same.ResourceLoaderAware
:ResourceLoader
An extension class used to obtain,ResourceLoader
which can be used to obtain all resource objects in the classpath. This class can be extended to obtain theResourceLoader
objects.ApplicationEventPublisherAware
:ApplicationEventPublisher
An extension class used for acquisition,ApplicationEventPublisher
which can be used to publish events and beApplicationListener
used together. ItApplicationListener
will be mentioned in detail in the introduction below. This object can also be obtained through spring injection.MessageSourceAware
:MessageSource
An extension class used for acquisition,MessageSource
mainly used for internationalization.ApplicationContextAware
ApplicationContext
: An extension class used to obtainApplicationContext
, 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 ,ApplicationContext
it also implements interfaces such as , and can also be used to do related interface things.BeanFactory
MessageSource
ApplicationEventPublisher
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, postProcessBeforeInitialization
before, 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 postProcessBeforeInitialization
after and InitializingBean.afterPropertiesSet
before.
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. InitializingBean
The interface provides a way to initialize the bean. It only includes afterPropertiesSet
methods. Any class that inherits the interface will execute this method when initializing the bean. The triggering time of this extension point is postProcessAfterInitialization
before.
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.FactoryBean
factory class interface for this purpose, and users can customize the logic of instantiated beans by implementing this interface. FactoryBean
Interfaces occupy an important position in the Spring framework, and Spring itself provides more than 70 FactoryBean
implementations. They hide the details of instantiating some complex beans and bring convenience to upper-layer applications. Starting from Spring 3.0, FactoryBean
generics 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 postProcessAfterInitialization
later.
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 @Order
to 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. ApplicationListener
It 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
ConfigurableApplicationContext
using 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 theApplicationContext
container is ready for use. -
ContextStartedEvent
This event is published when started using
ConfigurableApplicationContext
the start() method in the (ApplicationContext subinterface) interface .ApplicationContext
You can investigate your database, or you can restart any stopped applications after receiving this event. -
ContextStoppedEvent
This event is published when using stop
ConfigurableApplicationContext
in the interface . You can do the necessary cleanup work after receiving this eventstop()
ApplicationContext
-
ContextClosedEvent
This event is published when closed using methods
ConfigurableApplicationContext
in 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.