簡單瞭解spring中的BeanPostProcessor(後置處理器)

現象

最近項目中使用了spring中的異步處理@EnableAsync和定時任務@EnableSchedule二者作用在同一個service中,導致異步方法失效,最終發現還是不瞭解後置處理器作用導致的,還是圖樣圖森破

BeanPostProcessor

該接口的兩個方法如下,都與Bean的生命週期有密切聯繫,
不瞭解bean生命週期的同學參考

  • postProcessBeforeInitialization()
    這個方法作用於bean的初始化之前,
    • init-method指定的方法
    • 重寫InitializingBean接口的afterPropertiesSet()方法
    • @PostConstruct註解標註的方法
  • postProcessAfterInitialization()
    該方法作用於初始化完成之後

源碼解讀

我們知道,spring的入口在AbstractApplicationContextrefresh()方法中,如圖:
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中,故異步功能失效了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章