代碼: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 執行的都早,由於接口特殊,這裏不再繼續往下進行分析。