Spring Ioc原始碼分析系列--Ioc容器註冊BeanPostProcessor後置處理器以及事件訊息處理

Codegitz 發表於 2022-05-18
Spring

Spring Ioc原始碼分析系列--Ioc容器註冊BeanPostProcessor後置處理器以及事件訊息處理

前言

上一篇分析了BeanFactoryPostProcessor的作用,那麼這一篇繼續在refresh()方法裡遊蕩,相信對Spring熟悉點的朋友,在看完BeanFactoryPostProcessor後,一定會想到Spring裡面還有個BeanPostProcessor,那這個東西是什麼作用呢?下面會進行介紹,同時由於註冊BeanPostProcessor的邏輯比較簡單,這裡會穿插一下BeanPostProcessor生效的時機和原始碼邏輯,實際上這部分應該是Bean例項化出現的邏輯。

介紹完這部分之後,會介紹Spring的訊息源初始化、廣播器的初始以及監聽器的初始化。這部分工作完成之後,Spring容器就會進入到Bean的建立過程,因為準備工作已經做得差不多了,容器已經準備好,接下來就是初始化Bean放進去容器裡面。

BeanFactoryPostProcessor和BeanPostProcessor之間的區別

這兩個的區別還是很顯而易見的,主要表現在應用的階段不同BeanFactoryPostProcessor是對BeanDefinition直接生效的,這更加底層,也更加原始,所以直接使用BeanFactoryPostProcessor會比較少。BeanPostProcessor是對bean例項生效的,相對於對BeanDefinition的處理,這個階段更加靠後,BeanFactoryPostProcessor階段bean是尚未初始化出來的,BeanPostProcessor處理的時候已經生成了例項物件,BeanPostProcessor會在物件的例項基礎上進行一個更進一步的加工。

不熟悉的朋友看起來可能有點抽象,那麼這裡舉一個例子吧。

BeanFactoryPostProcessor的類比:

假設你要造一個杯子,那麼杯子需要一份原材料列表,材質你可以選擇鐵、銅、金、銀等等,樣式你可以選擇圓型、方形、橢圓等等。假設開始原料選擇鐵,形狀為圓形,那麼這一份原料列表對應的就是一個BeanDefinition。原料列表出來後,沒什麼問題就會按照這一份列表去建立一個杯子。但是有時候需要一些額外的操作,例如對某些BeanDefinition進行檢查,假設有一個檢查員BeanFactoryPostProcessor去檢查每個BeanDefinition。他看到杯子的材質是鐵,覺得有失身份,於是把材料改成了金子,於是後續再去建立杯子的時候,就是個金盃了。

BeanPostProcessor的類比:

BeanPostProcessor的處理階段則要靠後,在上面杯子建立完成之後,才到了BeanPostProcessor出場。BeanPostProcessor會在例項的基礎上進行一些加工,拿杯子來舉例,上一個階段拿到的是一個粗糙的杯子,這裡會進行一些處理,例如給杯子加點花紋樣式,給杯子拋光等等。**注意這些操作都是在一個已有的杯子上進行的,但是請注意,這不是絕對的。**BeanPostProcessor除了能對Bean進行深加工外,還能直接進行Bean替換,類比來說,就是換了個杯子,偷樑換柱。Spring Aop的功能就是這樣實現的,把經過代理的Bean放了進去,替換了原有的Bean。

所以比較一下得出一個很明顯的結論:

  • BeanFactoryPostProcessor對BeanDefinition生效

  • BeanPostProcessor對bean例項生效

原始碼分析

registerBeanPostProcessors(beanFactory)

話不多說,下面繼續分析refresh()方法裡面的子方法,上一篇分析到了第五個子方法,那這篇從第六個registerBeanPostProcessors(beanFactory)開始。

跟進程式碼,可以看到實現都委託給了PostProcessorRegistrationDelegate#registerBeanPostProcessors(beanFactory, this)方法。

	/**
	 * Instantiate and register all BeanPostProcessor beans,
	 * respecting explicit order if given.
	 * <p>Must be called before any instantiation of application beans.
	 *
	 * 例項化並註冊所有 BeanPostProcessor bean,如果給定順序,則按照順序排序。
	 * <p>必須在應用程式 bean 的任何例項化之前呼叫。
	 */
	protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
	}

繼續跟進,這個方法的邏輯也是比較簡單的,跟上篇的BeanFactoryPostProcessor註冊類似,這裡也會按照優先順序去對BeanPostProcessor進行排序然後按順序進行註冊。都是些家常套路了,可以跟著註釋去看一下。值得注意的是,這裡會額外加入兩個BeanPostProcessor,分別為BeanPostProcessorCheckerApplicationListenerDetectorBeanPostProcessorChecker主要是用來記錄一些日誌,ApplicationListenerDetector是用來檢測實現了ApplicationListener但是getBeanNamesForType()沒探測出來的漏網之魚。這裡的漏網之魚可能是一些動態註冊的bean或者一些內部類,這裡再次獲取後會放入到applicationListeners集合裡。

	public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

		// 獲取容器中所有的 BeanPostProcessor
		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

		// Register BeanPostProcessorChecker that logs an info message when
		// a bean is created during BeanPostProcessor instantiation, i.e. when
		// a bean is not eligible for getting processed by all BeanPostProcessors.
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		// 註冊 BeanPostProcessorChecker,當 bean 不符合所有 BeanPostProcessor 處理的條件時,它會在 BeanPostProcessor 例項化期間建立 bean 時記錄一條資訊訊息
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

		// Separate between BeanPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		// 按照順序分類區分 BeanPostProcessor
		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		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);
			}
		}

		// First, register the BeanPostProcessors that implement PriorityOrdered.
		// 首先註冊實現了 PriorityOrdered 介面的 BeanPostProcessor
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

		// Next, register the BeanPostProcessors that implement Ordered.
		// 其次註冊實現了 Ordered 介面的 BeanPostProcessor
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String ppName : orderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);

		// Now, register all regular BeanPostProcessors.
		// 現在到了註冊沒有實現上述介面的 BeanPostProcessor
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String ppName : nonOrderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

		// Finally, re-register all internal BeanPostProcessors.
		// 最後,重新註冊所有內部 BeanPostProcessor MergedBeanDefinitionPostProcessor。
		sortPostProcessors(internalPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

		// Re-register post-processor for detecting inner beans as ApplicationListeners,
		// moving it to the end of the processor chain (for picking up proxies etc).
		// 重新註冊用於將內部 bean 檢測為 ApplicationListeners 的後處理器,將其移動到處理器鏈的末尾(用於拾取代理等)。
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}

initMessageSource()

接下來繼續進行下一步的準備工作,初始化訊息源。這裡是預設使用了父類的訊息源,如果沒有就初始化一個DelegatingMessageSource,這個DelegatingMessageSource會預設將所有的呼叫都委派到父容器的訊息源去解析,如果沒有父容器的訊息源,那麼它不會解析任何訊息。

	/**
	 * Initialize the MessageSource.
	 * Use parent's if none defined in this context.
	 * 初始化訊息源。如果沒有在此上下文中定義,則使用父容器的。
	 */
	protected void initMessageSource() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		// 返回當前容器職工是否存在 messageSource,忽略祖先容器
		if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
			this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
			// Make MessageSource aware of parent MessageSource.
			// 如果存在祖先,並且 messageSource 型別是 HierarchicalMessageSource,則獲取祖先的 messageSource 設定到當前 messageSource 裡。
			if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
				HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
				if (hms.getParentMessageSource() == null) {
					// Only set parent context as parent MessageSource if no parent MessageSource
					// registered already.
					hms.setParentMessageSource(getInternalParentMessageSource());
				}
			}
			if (logger.isTraceEnabled()) {
				logger.trace("Using MessageSource [" + this.messageSource + "]");
			}
		}
		else {
			// Use empty MessageSource to be able to accept getMessage calls.
			// 本地不存在 messageSource,使用空 MessageSource 能夠接受 getMessage 呼叫
			DelegatingMessageSource dms = new DelegatingMessageSource();
			dms.setParentMessageSource(getInternalParentMessageSource());
			this.messageSource = dms;
			beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
			if (logger.isTraceEnabled()) {
				logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
			}
		}
	}

initApplicationEventMulticaster()

初始化 ApplicationEventMulticaster,如果上下文中沒有定義,則使用 SimpleApplicationEventMulticaster

	/**
	 * Initialize the ApplicationEventMulticaster.
	 * Uses SimpleApplicationEventMulticaster if none defined in the context.
	 *
	 * 初始化 ApplicationEventMulticaster。
	 * 如果上下文中沒有定義,則使用 SimpleApplicationEventMulticaster。
	 *
	 * @see org.springframework.context.event.SimpleApplicationEventMulticaster
	 */
	protected void initApplicationEventMulticaster() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		// 如果本地容器裡存在 applicationEventMulticaster,直接使用本地容器裡的 applicationEventMulticaster
		if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
			this.applicationEventMulticaster =
					beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
			if (logger.isTraceEnabled()) {
				logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
			}
		}
		else {
			// 否則使用 SimpleApplicationEventMulticaster 廣播器
			this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
			// 將給定的單例物件新增到該工廠的單例快取中
			beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
			if (logger.isTraceEnabled()) {
				logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
						"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
			}
		}
	}

這個事件廣播器是幹什麼的呢?其實很簡單,就是把一個事件廣播到所有的ApplicationListener上。可以看一下里面的關鍵方法SimpleApplicationEventMulticaster#multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType),這裡就是獲取所有的listener,如果有非同步執行緒池,則非同步執行,否則逐個呼叫。

	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		// 解析事件的型別,這個type會用於後續的 ListenerCacheKey 快取 key 構建
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		// 獲取執行緒池
		Executor executor = getTaskExecutor();
		// 逐個廣播事件到 listener,就是將 listener 都遍歷呼叫一遍
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

	protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
		// 錯誤處理器,記錄任務處理期間發生的錯誤
		ErrorHandler errorHandler = getErrorHandler();
		if (errorHandler != null) {
			try {
				doInvokeListener(listener, event);
			}
			catch (Throwable err) {
				errorHandler.handleError(err);
			}
		}
		else {
			doInvokeListener(listener, event);
		}
	}

	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			// 將事件傳入listener,完成事件的監聽回撥
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			// ...
		}
	}

onRefresh()

這是個空方法,交給子類實現。這裡可以用來初始化特定上下文子類中的其他特殊 bean,也是留出來的一個擴充套件口。

	/**
	 * Template method which can be overridden to add context-specific refresh work.
	 * Called on initialization of special beans, before instantiation of singletons.
	 *
	 * 可以重寫以新增特定於上下文的重新整理工作的模板方法。在單例例項化之前呼叫特殊 bean 的初始化。
	 * 
	 * <p>This implementation is empty.
	 * @throws BeansException in case of errors
	 * @see #refresh()
	 */
	protected void onRefresh() throws BeansException {
		// For subclasses: do nothing by default.
	}

registerListeners()

上一步已經初始化完成了廣播器,那接下來就是檢查偵聽器並註冊它們。

事件可以按照註冊的型別進行區分,可以分為以下三種:

  • 通過addApplicationListener()手動新增進去的
  • 容器裡實現了ApplicationListener介面的
  • 容器啟動早期需要的事件earlyApplicationEvents,早期事件是需要在這裡直接釋出的
	/**
	 * Add beans that implement ApplicationListener as listeners.
	 * Doesn't affect other listeners, which can be added without being beans.
	 *
	 * 新增實現 ApplicationListener 的 bean作為偵聽器。
	 * 不影響其他監聽器,可以新增而不是 bean。
	 */
	protected void registerListeners() {
		// Register statically specified listeners first.
		// 首先註冊靜態指定的監聽器,也就是通過addApplicationListener(ApplicationListener<?> listener) 註冊的listener。
		for (ApplicationListener<?> listener : getApplicationListeners()) {
			getApplicationEventMulticaster().addApplicationListener(listener);
		}

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let post-processors apply to them!
		// 這裡只是獲取beanName,是為了避免初始化 bean 導致後置處理器失效
		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
		// 逐個註冊listener
		for (String listenerBeanName : listenerBeanNames) {
			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}

		// Publish early application events now that we finally have a multicaster...
		// 釋出早期應用程式事件,因為我們終於有了一個廣播器......
		// 忍辱負重,早期事件存到了這裡才能進行釋出,因為之前沒有廣播器
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (earlyEventsToProcess != null) {
			// 逐個釋出事件
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}

finishBeanFactoryInitialization(beanFactory)

準備工作已經基本完成,接下來就到了finishBeanFactoryInitialization(beanFactory)方法了。從方法名可以看到,這個方法是負責完成此上下文的 bean 工廠的初始化,初始化所有剩餘的單例 bean。可以看到這個方法開始也進行了一些準備工作,例如註冊型別裝換器、佔位符處理器以及LoadTimeWeaverAware載入等。最後會呼叫beanFactory.preInstantiateSingletons()進行物件建立,由於這裡是比較複雜的過程,會分幾篇文章去詳細分析,這篇文章就是大概從表面上走完refresh()方法的原始碼。

	/**
	 * Finish the initialization of this context's bean factory,
	 * initializing all remaining singleton beans.
	 *
	 * 完成此上下文的 bean 工廠的初始化,初始化所有剩餘的單例 bean。
	 * 
	 */
	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
		// 初始化一個ConversionService用於型別轉換,這個ConversionService會在例項化物件的時候用到
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		// Register a default embedded value resolver if no bean post-processor
		// (such as a PropertyPlaceholderConfigurer bean) registered any before:
		// at this point, primarily for resolution in annotation attribute values.
		// 新增一個StringValueResolver,用於處理佔位符,可以看到,預設情況下就是使用環境中的屬性值來替代佔位符中的屬性
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}

		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		// 建立所有的LoadTimeWeaverAware
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		// 靜態織入完成後將臨時的類載入器設定為null,所以除了建立LoadTimeWeaverAware時可能會用到臨時類載入器,其餘情況下都為空
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		// 將所有的配置資訊凍結
		beanFactory.freezeConfiguration();

		// Instantiate all remaining (non-lazy-init) singletons.
		// 開始進行真正的建立
		beanFactory.preInstantiateSingletons();
	}

finishRefresh()

到這裡容器已經準備好了,bean也已經例項化完成,就差最後的一些事件通知和後續的兜底處理。這裡比較重要的是會呼叫到所有實現了LifecycleProcessor#onRefresh()的Bean,在這裡可以讓生命週期Bean實現很多擴充套件。其次比較重要的是會釋出一個ContextRefreshedEvent事件,通知所有監聽器容器已經啟動完成,這裡就可以實現一些容器啟動完成後的回撥或者是一些任務等,任君發揮。

	/**
	 * Finish the refresh of this context, invoking the LifecycleProcessor's
	 * onRefresh() method and publishing the
	 * {@link org.springframework.context.event.ContextRefreshedEvent}.
	 *
	 * 完成容器的重新整理啟動,呼叫所有 LifecycleProcessor#onRefresh() 方法來發布 ContextRefreshedEvent 事件
	 *
	 */
	protected void finishRefresh() {
		// Clear context-level resource caches (such as ASM metadata from scanning).
		// 清除容器上下文級別的資源快取(例如ASM掃描的後設資料)
		clearResourceCaches();

		// Initialize lifecycle processor for this context.
		// 初始化上下文的 lifecycle processor
		initLifecycleProcessor();

		// Propagate refresh to lifecycle processor first.
		// 首先將重新整理傳播到生命週期處理器。
		getLifecycleProcessor().onRefresh();

		// Publish the final event.
		// 釋出最終事件。
		publishEvent(new ContextRefreshedEvent(this));

		// Participate in LiveBeansView MBean, if active.
		// 參與 LiveBeansView MBean(如果處於活動狀態)。
		LiveBeansView.registerApplicationContext(this);
	}

總結

本文的重點有點分散,更像是走馬觀花,但是分散裡的重點毫無疑問是理解和區分BeanFactoryPostProcessorBeanPostProcessor之間的區別,文章開頭通過一個例子去類比了一下這二者的作用階段和分別可以完成什麼工作,個人覺得還是比較貼切的,希望能夠幫助到理解。

到這裡已經基本把refresh()方法走了一遍,當然這裡看到的大部分都是一些基礎準備工作,最關鍵的Bean例項化是還沒有開始分析的,Bean的例項化會後續分好幾篇文章繼續去分析。

今天這篇文章是比較簡單的,沒有太多邏輯,基本上都是一個一個小方法,巢狀不深,因為深入的我都不寫了哈哈。

這系列寫到這裡,才完成了準備工作,接下來的Bean建立才是真正開始了重頭戲。那接下來繼續慢慢分析吧。

如果有人看到這裡,那在這裡老話重提。與君共勉,路漫漫其修遠兮,吾將上下而求索。