代码:https://gitee.com/free/boot-order/tree/master/src/main/java/com/github/abel533/postprocessor
PostProcessor 类接口如下所示:
其中 BeanPostProcessor 是最常见的一个系列,BeanFactoryPostProcessor 和 EnvironmentPostProcessor 不常用。
由于上图所示的继承关系和不同 PostProcessor 使用的要求限制,这里不能同时使用所有这些 PostProcessor,所以下面是针对不同情况去测试方法的执行顺序。
因为 BeanFactoryPostProcessor 没有使用限制,所以后续所有例子中都会实现该接口,而且该接口都是第一个调用的。
BeanPostProcessor 系列
用途:允许修改新的 bean 实例的工厂钩子函数,例如检查标记接口或者用代理包装 bean。
通常在postProcessBeforeInitialization
方法中处理标记接口,在postProcessAfterInitialization
中处理代理 beans。
该方法会对上下文中的所有 bean 进行处理,因此根据 bean 的数量,会执行多次,所以后续日志中都会频繁出现调用的日志。
在 4 个子接口中,都针对 BeanPostProcessor 增加了额外的处理方法,额外的方法都是在
BeanPostProcessor 接口
src\main\java\com\github\abel533\postprocessor\base
由于执行多次的原因,下面贴出部分执行顺序:
BeanFactoryPostProcessor#postProcessBeanFactory
BeanPostProcessor#postProcessBeforeInitialization - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
BeanPostProcessor#postProcessBeforeInitialization - org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
BeanPostProcessor#postProcessAfterInitialization - org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
BeanPostProcessor#postProcessBeforeInitialization - transactionAttributeSource
BeanPostProcessor#postProcessAfterInitialization - transactionAttributeSource
BeanPostProcessor#postProcessBeforeInitialization - transactionInterceptor
BeanPostProcessor#postProcessAfterInitialization - transactionInterceptor
BeanPostProcessor#postProcessBeforeInitialization - org.springframework.transaction.config.internalTransactionAdvisor
BeanPostProcessor#postProcessAfterInitialization - org.springframework.transaction.config.internalTransactionAdvisor
BeanPostProcessor#postProcessAfterInitialization - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
从 AbstractApplicationContext#refresh
中可以看到 PostProcessor 的执行顺序,代码如下(有删减):
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// 执行 0
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// 注册所有 BeanPostProcessors,这里会区分是否继承了 PriorityOrdered 和 Ordered
// 执行的优先级按照 PriorityOrdered > Ordered > 无
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// 执行 1~end
// Initialize other special beans in specific context subclasses.
onRefresh();
}
}
}
1~10 具体在 AbstractAutowireCapableBeanFactory#initializeBean
初始化 Bean 的时候,先调用了 postProcessBeforeInitialization
方法,然后是 Bean 的初始化方法,随后就是 postProcessAfterInitialization
方法,代码如下(有删减):。
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (mbd == null || !mbd.isSynthetic()) {
// postProcessBeforeInitialization 方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
}
if (mbd == null || !mbd.isSynthetic()) {
// postProcessAfterInitialization 方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
上述执行顺序中,执行 1 的时候处理的 org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
,在之后的 postProcessAfterInitialization
方法中,由于获取 advisor 进行代理,又进入了其他 bean 的 PostProcessor 方法,直到 10 的时候,才返回到 1 对应的 bean 上。
SmartInstantiationAwareBeanPostProcessor
SmartInstantiationAwareBeanPostProcessor 继承了 InstantiationAwareBeanPostProcessor,这俩接口都是用于 Spring 框架内部使用的接口,接口方法可以根据需要随时添加(不对外兼容)不推荐使用,
如果要使用,可以使用 InstantiationAwareBeanPostProcessorAdapter 类,该类会保证所有默认方法实现的正确性。
下面以 InstantiationAwareBeanPostProcessorAdapter 为例查看执行顺序。
为了能完整的测试所有的接口方法,特别实现了下面两个循环依赖的类:
public class User {
@Autowired
private UserExt ext;
private String id;
public User() {
}
//其他
}
public class UserExt {
@Autowired
private User user;
private String name;
public UserExt() {
}
//其他
}
由于所有 Bean 都会触发接口输出日志,因此在日志中过滤只显示了其中 3 个 bean 的日志,执行顺序如下:
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
InstantiationAwareBeanPostProcessor#postProcessProperties - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
BeanPostProcessor#postProcessBeforeInitialization - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
BeanPostProcessor#postProcessAfterInitialization - org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation - user
InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation - user
InstantiationAwareBeanPostProcessor#postProcessProperties - user
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation - userExt
InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation - userExt
InstantiationAwareBeanPostProcessor#postProcessProperties - userExt
SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference - user
BeanPostProcessor#postProcessBeforeInitialization - userExt
BeanPostProcessor#postProcessAfterInitialization - userExt
BeanPostProcessor#postProcessBeforeInitialization - user
BeanPostProcessor#postProcessAfterInitialization - user
SmartInstantiationAwareBeanPostProcessor#predictBeanType
执行很频繁,从顺序中去掉
不存在依赖的前提下,就是按照 ServletWebServerFactoryConfiguration$EmbeddedTomcat
的顺序执行的,摘抄如下:
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
在实例化目标bean之前应用此BeanPostProcessor。SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
确定要用于给定bean的候选构造函数。InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
在bean实例化之后,通过构造函数或工厂方法,但在Spring属性填充(来自显式属性或自动装配)之前执行操作。InstantiationAwareBeanPostProcessor#postProcessProperties
在工厂将它们应用于给定bean之前对给定属性值进行后处理,不需要属性描述符。BeanPostProcessor#postProcessBeforeInitialization
在任何bean初始化回调(如InitializingBean afterPropertiesSet 或自定义init方法)之前,将此BeanPostProcessor应用于给定的新bean实例。BeanPostProcessor#postProcessAfterInitialization
在任何bean初始化回调(如InitializingBean afterPropertiesSet 或自定义init方法)之后,将此BeanPostProcessor应用于给定的新bean实例。
接下来看看 User 和 UserExt 两个循环依赖 bean 的创建过程。
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation - user
在实例化目标bean之前应用此BeanPostProcessor。InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation - user
在bean实例化之后,通过构造函数或工厂方法,但在Spring属性填充(来自显式属性或自动装配)之前执行操作。InstantiationAwareBeanPostProcessor#postProcessProperties - user
在工厂将它们应用于给定bean之前对给定属性值进行后处理,不需要属性描述符。InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation - userExt
在实例化目标bean之前应用此BeanPostProcessor。InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation - userExt
在bean实例化之后,通过构造函数或工厂方法,但在Spring属性填充(来自显式属性或自动装配)之前执行操作。InstantiationAwareBeanPostProcessor#postProcessProperties - userExt
在工厂将它们应用于给定bean之前对给定属性值进行后处理,不需要属性描述符。SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference - user
获取早期访问指定bean的引用,通常用于解析循环引用。BeanPostProcessor#postProcessBeforeInitialization - userExt
在任何bean初始化回调(如InitializingBean afterPropertiesSet 或自定义init方法)之前,将此BeanPostProcessor应用于给定的新bean实例。BeanPostProcessor#postProcessAfterInitialization - userExt
在任何bean初始化回调(如InitializingBean afterPropertiesSet 或自定义init方法)之后,将此BeanPostProcessor应用于给定的新bean实例。BeanPostProcessor#postProcessBeforeInitialization - user
在任何bean初始化回调(如InitializingBean afterPropertiesSet 或自定义init方法)之前,将此BeanPostProcessor应用于给定的新bean实例。BeanPostProcessor#postProcessAfterInitialization - user
在任何bean初始化回调(如InitializingBean afterPropertiesSet 或自定义init方法)之后,将此BeanPostProcessor应用于给定的新bean实例。
从这儿的逻辑看到,初始化 User 的时候,由于需要注入 UserExt,就去初始化 UserExt 了,由于 UserExt 中也需要 User,并且 User 已经有了早期的 bean 引用,因此 UserExt 初始化完成,此后返回 User 的初始化过程,至此两个 bean 创建成功。
这里的示例中,都是通过属性注入的,因此可以成功。如果 User 使用构造参数注入 UserExt,由于这里扫描顺序 User 更早,就无法解决这个循环依赖,会报错如下:
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| user defined in class path resource [com/github/abel533/postprocessor/instantiation/CircleConfig.class]
↑ ↓
| userExt (field private com.github.abel533.postprocessor.instantiation.User com.github.abel533.postprocessor.instantiation.UserExt.user)
└─────┘
但是如果调整这两个 Bean 的顺序(在 CircleConfig 中),就会成功。由于初始化顺序的不确定性,构造参数方式很难解决循环依赖,所以存在循环依赖的情况时,使用属性或方法方式注入。
EnvironmentPostProcessor
这是 Spring Boot 特有的接口,会在刷新应用程序上下文之前调用。支持通过 Ordered 接口进行排序。
必须在 META-INF/spring.factories 使用此类的完全限定名称作为键来注册 EnvironmentPostProcessor 实现 。
例如本例:
org.springframework.boot.env.EnvironmentPostProcessor=com.github.abel533.postprocessor.environment.EnvironmentPostProcessorImpl
由于这个配置会影响其他测试的执行顺序(EnvironmentPostProcessor 肯定是第一个),所以本项目中注释了上述配置。
该接口比所有其他 PostProcessor 执行的都早,由于接口特殊,这里不再继续往下进行分析。