Spring 源碼解析——IOC 源碼解析(BeanPostProcessor 系列之體系概述)(六)

寫文章不易,轉載請標明出處。

同時,如果你喜歡我的文章,請關注我,讓我們一起進步。

一、概述

在前面的 BeanPostProcessor 系列博文中我們已經對幾個常用的 BeanPostProcessor 實現類的源碼進行了解析,但是在分析的過程中我慢慢的發現因爲缺少對 BeanPostProcessor 整個體系的認知和了解,導致對每一個 BeanPostProcessor 實現類的解析都總是覺得差一點東西,感覺沒有能夠分析的很透徹,同時還存在的一個問題就是因爲我們都是對單個的 BeanPostProcessor 實現類進行分析,這樣導致的問題就是我們沒有辦法將它們關聯起來,好像每一部分都是分離開的,但其實對於 Spring 來說 BeanPostProcessor 是伴隨着 Bean 整個生命週期的組件。

因此,藉着小長假的空閒時間,特意在查詢了一些資料並在經過了幾次調試和思考後大致確定了 BeanPostProcessor 的一個比較完整的調用流程,通過源碼的閱讀和調試我大概確定了 Spring 當中對於五個主要 BeanPostProcessor 的九處調用,這九處調用貫穿了 Bean 的整個生命週期。因爲這篇博文是一個比較流程化的解析博文,重在讓讀者能夠對 Spring 當中的 BeanPostProcessor 整體有一個相對比較清晰的認識,所以在這篇博文中不會涉及到特別多的源碼(僅存的一些源碼是涉及 BeanPostProcessor 的相關接口,主要是爲了能夠讓大家對 BeanPostProcessor 中方法的入參和返回值有一個比較清晰地認識),更多地會是以流程圖和文字分析的方式來展現。

 

二、功能介紹

對於 BeanPostProcessor 大家一定都不陌生了,這個接口貫穿了 Bean 的整個生命週期,爲系統內部的組件和外部的開發者而都提供了一個干預 Bean 生命週期的渠道,在 BeanPostProcessor 頂層接口中主要涉及的是 Bean 生命週期中初始化的部分,而在其擴展接口中分別又涉及了實例化和屬性注入等一系列部分。並且在 Spring 當中許多重要的功能比如自動裝配、AOP 以及 Java 配置類等都是通過 BeanPostProcessor 來實現的,所以說 BeanPostProcessor 可以算是 Spring 當中的一大核心組件。

但是 BeanPostProcessor 複雜的集成體系以及種類繁多的實現類讓我們眼花繚亂,因此我們在接下來會首先梳理 Bean 生命週期中 BeanPostProcessor 的九處具體調用,然後再去詳細的分析五個重要的 BeanPostProcessor 接口的方法及其作用。

 

三、生命週期整體調用流程

 

 

四、主要接口解析

4.1 整體結構體系

4.2 BeanPostProcessor 

public interface BeanPostProcessor {

	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

BeanPostProcessor 接口是下面所述的所有接口的頂層接口,它提供的工廠鉤子函數允許自定義修改新的 Bean 實例,例如 檢查標記接口使用代理類包裝它們。ApplicationContexts 可以在其 BeanDefinition 中自動檢測 BeanPostProcessor Bean,並將其應用於隨後創建的所有 Bean 實例。普通 BeanFactory 允許對 BeanPostProcessor(後置處理器)進行程序化註冊,適用於通過該工廠創建的所有 Bean 實例,並且通常通過標記接口等填充 Bean 的 BeanPostProcessor 將實現 postProcessBeforeInitialization 回調方法,而使用代理類包裝 Bean 的 BeanPostProcessor 通常將實現 postProcessBeforeInitialization 回調方法。 

對於 postProcessBeforeInitialization 方法,它會在所有的 Bean 初始化回調方法(例如 InitializingBean 的 afterPropertiesSet 或自定義的初始化方法)之前被調用,作用於已經完成屬性值填充的給定 Bean 實例,它默認返回的是原始 Bean 實例,但也可以返回包裝後的 Bean 實例。

postProcessAfterInitialization 方法將在所有 Bean 初始化回調方法(例如 InitializingBean 的 afterPropertiesSet 或自定義的init-method)之後被調用,作用於已經完成屬性值填充的給定 Bean 實例,它默認返回的是原始 Bean 實例,但也可以返回包裝後的 Bean 實例。對於 FactoryBean,將爲 FactoryBean 實例和由 FactoryBean 創建的對象(從Spring 2.0開始)調用此回調(後置處理器可以通過相應的 bean instanceof FactoryBean 檢查來確定是應用到 FactoryBean 還是創建的對象,還是兩者都應用)。與所有其他 BeanPostProcessor 回調相比,此回調還將在 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法觸發短路(方法返回值不爲 null)後被調用。

4.3 MergedBeanDefinitionPostProcessor

 

public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {

	void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);

	default void resetBeanDefinition(String beanName) {}
}

 MergedBeanDefinitionPostProcessor 是 BeanPostProcessor 接口的一個實現接口,它是在運行時用於合併 BeanDefinition 的回調接口。實現此子接口可以對 Spring 中 BeanFactory 創建的 Bean 實例的 MergedBeanDefinition(原始 BeanDefinition 的已處理副本,存放在 BeanFactory 的 mergedBeanDefinitions 集合中)進行處理。 例如通過 postProcessMergedBeanDefinition 方法可以內省 BeanDefinition,以便在對 Bean 的實際實例進行處理之前準備一些緩存的元數據,並且其還允許修改 BeanDefinition ,但只允許修改實際用於並行修改的 Definition 屬性,因此本質上這僅適用於在 RootBeanDefinition 中定義的操作而不適用於其基類的屬性。

postProcessMergedBeanDefinition 這個方法的作用簡單明瞭,就是對指定 Bean 的給定的 MergedBeanDefinition 進行處理。而 resetBeanDefinition 方法就是起到一個通知的作用,即通知給定的 BeanName 所對應的 BeanDefinition 已經被重新設置,所以此 BeanPostProcessor(後置處理器)應清除受影響的 Bean 的所有元數據,其默認實現爲空。

4.4 InstantiationAwareBeanPostProcessor

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

	@Nullable
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		return true;
	}

	@Nullable
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
		return null;
	}

	@Deprecated
	@Nullable
	default PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
		return pvs;
	}
}

 InstantiationAwareBeanPostProcessor 是 BeanPostProcessor 一個比較重要的實現接口,因爲在這個接口中對 BeanPostProcessor 的作用範圍進行了擴展,從只關注 Bean 的初始化擴展到了可以關注 Bean 的實例化(添加了實例化之前和實例化之後顯式設置屬性或自動裝配之前的回調),通常用於禁止特定目標 Bean 的默認實例化,例如使用特殊 TargetSources 創建代理( 合併目標,延遲初始化目標等)或實施其他注入策略(例如屬性注入)。

但是需要注意的是這個接口是一個專用接口,主要供框架內部使用,所以根據 Spring 的建議應儘可能實現普通的頂層 BeanPostProcessor 接口或從 InstantiationAwareBeanPostProcessorAdapter 派生來避免對該接口進行擴展。同時在這個接口規定了四個方法,其中最重要的兩個就是 postProcessBeforeInstantiation 和 postProcessAfterInstantiation 方法,這兩個方法分別會在 Bean 實例化之前和之後進行回調,然後剩下的兩個方法會在開始設置實例的屬性之前進行回調。

postProcessBeforeInstantiation 的作用時機是在實例化目標 Bean 之前,其返回的 Bean 對象可以是代替原目標 Bean 使用的代理 Bean 對象,從而有效地抑制了目標 Bean 的默認實例化。如果此方法返回一個非空(null)對象,則 Bean 創建過程將被短路,接下來唯一調用的進一步處理的方法是自定義配置的 BeanPostProcessor 的 postProcessAfterInitialization 回調(這點可見下面的源碼)。此回調將應用於具有其 Bean 類(BeanClass)的 Bean 定義(BeanDefinition)以及工廠方法定義(factory-method definitions),在這種情況下返回的 Bean 類型將在此處傳遞。同時自定義的 BeanPostProcessor 可能實現擴展的 SmartInstantiationAwareBeanPostProcessor 接口,以便預測它們將在此處返回的 Bean 對象的類型。 最後再次強調,該方法的默認實現返回 null ,此時繼續進行默認實例化流程,也可以返回要公開的 Bean 對象(例如自己創建的代理 Bean 對象)而不是原目標 Bean 的默認實例來替換掉原目標 Bean 對象。

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
	Object bean = null;
	if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
		// Make sure bean class is actually resolved at this point.
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			Class<?> targetType = determineTargetType(beanName, mbd);
			if (targetType != null) {
                                // 調用 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法
				bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                                // 如果 postProcessBeforeInstantiation 返回不爲 null
				if (bean != null) {
                                        // 緊接着調用 BeanPostProcessor 的 postProcessAfterInitialization 方法
					bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
				}
			}
		}
		mbd.beforeInstantiationResolved = (bean != null);
	}
	return bean;
}

postProcessAfterInstantiation 方法會在通過構造函數或工廠方法進行實例化 Bean 之後且在發生 Spring 屬性填充(通過顯式屬性或自動裝配)之前執行,這是在 Spring 自動裝配(屬性注入)開始之前對給定 Bean 實例執行自定義屬性注入的理想回調。該方法正常情況下默認實現返回 true ,表示應該爲 Bean 進行屬性填充,反之如果返回 false 則意味着應當跳過屬性注入,並且將阻止對此 Bean 實例調用任何後續的 InstantiationAwareBeanPostProcessor 實例方法。

postProcessProperties 這個方法是 postProcessPropertyValues 的一個最新版本的替換方法,因爲在下面我們可以看到 postProcessPropertyValues 方法已經將要被廢棄了。這個方法會作用在 Spring 爲屬性進行注入之前,對給定的屬性值進行最後處理,並且無需使用屬性描述符。但如果實現類提供了自定義的 postProcessPropertyValues 方法的實現,則實現類中的此方法應返回 null(默認值),此時會繼續嘗試調用 postProcessPropertyValues 方法,否則返回 pvs(處理後的屬性值),且在此接口的將來版本中(刪除了 postProcessPropertyValues)默認實現將直接按原樣返回給定的 pvs(PropertyValues 屬性值),這點目前也可以從下面的源碼中求證。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	...
	if (hasInstAwareBpps) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                                // 首先嚐試調用 postProcessProperties 方法
				PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                                // 如果獲取到的 postProcessProperties 方法返回值爲空
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
                                        // 則再調用 postProcessPropertyValues 方法
					pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return;
					}
				}
				pvs = pvsToUse;
			}
		}
	}
	...
}

postProcessPropertyValues 方法正如其註解所述是一個將要被廢棄的方法,它的功能跟上面的  postProcessProperties 是相似的,也是在 Spring 進行屬性注入之前對屬性值進行最後的處理,它允許檢查 Bean 屬性是否滿足所有依賴關係,例如基於 Bean 屬性設置的 setter 上的 @Required 註解,還允許替換要應用的屬性值,通常是通過基於原始 PropertyValues 創建新的 MutablePropertyValues 實例,添加或刪除特定值來實現。它的返回值是應用於給定 Bean 的實際屬性值(可以是傳入的 PropertyValues 實例,也可以是我們修改後的屬性實例)或者返回 null 來跳過屬性填充。

4.5 SmartInstantiationAwareBeanPostProcessor

public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {

	@Nullable
	default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

	@Nullable
	default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {

		return null;
	}

	default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

 首先 SmartInstantiationAwareBeanPostProcessor 是 InstantiationAwareBeanPostProcessor 的一個實現接口,也就是可以理解爲它是 InstantiationAwareBeanPostProcessor 接口的擴展,相對於父接口它添加了一個用於預測已處理 Bean 最終類型的回調方法 predictBeanType 。但是需要注意的是此接口是一個專用接口主要供框架內部使用,通常應用程序提供的後置處理器應僅實現簡單的 BeanPostProcessor 接口或從 InstantiationAwareBeanPostProcessorAdapter 類進行派生。最後,在下一個發行版中,新的方法可能會被添加到此接口。

predictBeanType 方法預測最終從 postProcessBeforeInstantiation(InstantiationAwareBeanPostProcessor 中的回調方法)回調返回的 Bean 的類型,其默認實現返回 null 。determineCandidateConstructors 方法用於確定實例化給定 Bean 的候選構造函數(一般用於實例化 Bean 之前),此方法默認實現也返回 null 。

getEarlyBeanReference 方法主要是用來解決單例 Bean 循環依賴的問題(解決方案分析在前面的博文中),這個方法的直觀作用就是通過給定的 BeanName 在允許暴露未實例化完成的 Bean 的條件下獲取 Bean 的引用,這個接口給 BeanPostProcessor 一個機會去獲取早期包裝 Bean(未完全實例化完成的 Bean)。 

4.6 DestructionAwareBeanPostProcessor

public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {

	void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;

	default boolean requiresDestruction(Object bean) {
		return true;
	}
}

 DestructionAwareBeanPostProcessor 接口僅實現了一個父接口即 BeanPostProcessor,這個接口主要是爲 Bean 的生命週期中添加了銷燬前的回調,典型用法是在特定的 Bean 類型上調用自定義銷燬回調,並與相應的初始化回調匹配。在這個接口中存在兩個方法 postProcessBeforeDestruction 和 requiresDestruction 。

postProcessBeforeDestruction 方法的主要作用是在銷燬實例之前,將此 BeanPostProcessor 應用於給定的 Bean 實例,例如調用自定義銷燬回調。就像 DisposableBean 接口的 destroy 方法和自定義的 destroy 方法(通過 Java 註解類和 XML 配置的 destroy 方法)一樣,此回調僅適用於容器完全管理其生命週期的 Bean, 單例和作用域 Bean 通常是這種情況。

requiresDestruction 方法的主要作用是判斷給定的 Bean 實例是否需要被此 BeanPostProcessor 銷燬,默認實現返回 true, 且在 Spring 5 之前如果 DestructionAwareBeanPostProcessor 的實現類未提供此方法的具體實現,則 Spring 也會默認假定返回 true 。所以總結來說,如果最終應爲此 Bean 實例調用 postProcessBeforeDestruction 方法則返回 true,如果不需要則返回 false 。

 

五、內容總結

最後來對這篇博文進行一下總結,通過這篇博文我們對 BeanPostProcessor 的體系結構進行了一個整體的分析,首先我們通過流程圖來列舉了 Spring 當中 BeanPostProcessor 的九處調用點(因爲流程圖中就已經很清晰的描述了 BeanPostProcessor 在 Bean 生命週期中的調用流程,所以這篇博文沒有過多的源碼分析),然後我們依次對 Spring 當中比較重要的 BeanPostProcessor 以及其子接口進行詳細的分析,基本捋清了幾個必要重要的 BeanPostProcessor 系列接口及其方法的作用。通過這次對 BeanPostProcessor 整體源碼的閱讀,能夠讓我們更加清晰地瞭解 Bean 的整個生命週期,也爲後續的對 BeanPostProcessor 實現類及其它生命週期回調方法的分析打下了比較好的基礎。

在你想要放棄的時候,想想是什麼讓你當初堅持走到了這裏。

 

 

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