現象
最近項目中使用了spring中的異步處理@EnableAsync
和定時任務@EnableSchedule
,二者作用在同一個service中,導致異步方法失效,最終發現還是不瞭解後置處理器作用導致的,還是圖樣圖森破。
BeanPostProcessor
該接口的兩個方法如下,都與Bean的生命週期有密切聯繫,
不瞭解bean生命週期的同學參考
postProcessBeforeInitialization()
這個方法作用於bean的初始化之前,init-method
指定的方法- 重寫
InitializingBean
接口的afterPropertiesSet()
方法 @PostConstruct
註解標註的方法
postProcessAfterInitialization()
該方法作用於初始化完成之後
源碼解讀
我們知道,spring的入口在AbstractApplicationContext
的refresh()
方法中,如圖:
其中框起來的方法,就是掃描容器中的BeanPostProcessor
過程,在執行到該方法時候,容器中已經默認添加了幾個BeanPostProcessor
實例對象,注意,是實例。如下圖示:
接下來就是執行registerBeanPostProcessors()
方法
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// 從容器中獲取所有`BeanPostProcessor`的bean定義
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// 註冊一個後置處理器檢查器,本身也是一個BeanPostProcessor,
// 當容器的日誌級別是info時,打印出沒有被所有BeanPostProcessor作用的bean對象
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
//將這個後置處理器檢查器注入到BeanFactory中,所有的bean初始化會遍歷bean工廠中的後置處理器集合,作用到每個bean的初始化中
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// 將實現了不同接口的後置處理器分別單獨處理 ,實現了同一接口的後置處理器屬於一類,同一類不能相互作用,優先級的順序是,PriorityOrdered,Ordered, others
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
//按照優先級進行分類,放到對應的集合中
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 首先註冊實現了PriorityOrdered接口的後置處理器
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
//添加到beanFactory的後置處理器集合中,
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
//其次,註冊實現Ordered接口的後置處理器,注意,ordered越大,優先級越小。
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(beanFactory, orderedPostProcessors);
//添加到beanFactory的後置處理器集合中,
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// 現在,註冊一些普通的後置處理器
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
//添加到beanFactory的後置處理器集合中,
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// 最後,重新註冊內部後置處理器
sortPostProcessors(beanFactory, internalPostProcessors);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
以上就是spring對後置處理器的初始化過程,當初始完這些後,refresh()
方法中的finishBeanFactoryInitialization()
方法,就會繼續初始化容器中所有的單例,非懶加載的bean對象,這些對象包含我們自定義的Controller
,Service
等,這些自定義對象就會按照上面後置處理器的處理邏輯,執行對應的postProcessBeforeInitialization()
和postProcessAfterInitialization()
方法。
結語
由於spring中的異步是通過實現了Ordered
接口的AsyncAnnotationBeanPostProcessor
處理的,定時任務是通過實現了Ordered
接口的ScheduledAnnotationBeanPostProcessor
處理的,二者都實現了Order
接口,屬於同一優先級,由於同一優先級的後置處理器不能相互作用,然後在spring在初始化ScheduledAnnotationBeanPostProcessor
後置處理器時,發現某個bean依賴了這個service,導致service被提前加載了,此時實現Ordered
接口的後置處理器還沒有放到BeanFactory
中,故異步功能失效了。