天天看點

Spring源碼學習第十一天==>填充Bean屬性

前言:Bean的建立所經曆的步驟大緻為執行個體化,填充屬性,初始化。之前在Spring第九天的時候描述過執行個體化的過程了,是以這篇文章來描述Bean的填充屬性環節

入口方法:AbstractAutowireCapableBeanFactory類的populateBean(beanName, mbd, instanceWrapper)方法。

1.首先屬性的類型可以分為大緻這麼幾類

  • 8種基本資料類型
  • 引用類型
  • 集合類型,集合類型的元素可以為基本資料類型與引用類型

2.屬性注入的方式,根據Spring源碼可以得出有5種,在AutowireCapableBeanFactory類中可以檢視

  • AUTOWIRE_NO=0:預設,表示不選擇自動裝配
  • AUTOWIRE_BY_NAME=1:表示按名稱進行自動注入
  • AUTOWIRE_BY_TYPE=2:表示按類型進行自動注入
  • AUTOWIRE_CONSTRUCTOR=3:按構造器進行注入
  • AUTOWIRE_AUTODETECT=4:自動選擇 

3.填充屬性詳細介紹

  •      執行個體化對象為空,但是BeanDefinition中卻有屬性鍵值對資訊,就抛出異常
if (bw == null) {
			// 如果mbd有需要設定的屬性
			if (mbd.hasPropertyValues()) {
				// 抛出bean建立異常
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
			}
			else {
				// Skip property population phase for null instance.
				// 沒有可填充的屬性,直接跳過
				return;
			}
}
           
  • 容器中是否存在InstantiationAwareBeanPostProcessor及其子類,該類是用于豐富Bean資訊的類,可以在Bean的執行個體化前後,初始化前後,及其屬性設定上進行操作,如果存在這種類型的後置處理器,就調用他們的執行個體化後要執行的豐富postProcessAfterInstantiation()
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			//周遊工廠中的BeanPostProcessor對象
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				//如果 bp 是 InstantiationAwareBeanPostProcessor 執行個體
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					// postProcessAfterInstantiation:一般用于設定屬性
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						return;
					}
				}
			}
}
           
  • 判斷xml檔案中定義Bean資訊的時候是否有顯示的設定<property/>,如果有的話就儲存在PropertyValues對象中
//PropertyValues:包含以一個或多個PropertyValue對象的容器,通常包括針對特定目标Bean的一次更新
//如果mdb有PropertyValues就擷取其PropertyValues
// xml配置檔案中的<property/>擷取到該标簽的鍵值對
 PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
           
  • 根據注入方式選擇對應的方法去擷取鍵值對的資訊,主要是根據名稱注入與類型注入兩種方式,文章最後會附上一張流程圖,會給出autowiredByName方式的處理流程
// 擷取 mbd 的 自動裝配模式
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		// 如果 自動裝配模式 為 按名稱自動裝配bean屬性 或者 按類型自動裝配bean屬性
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			//MutablePropertyValues:PropertyValues接口的預設實作。允許對屬性進行簡單操作,并提供構造函數來支援從映射 進行深度複制和構造
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Add property values based on autowire by name if applicable.
			// 根據autotowire的名稱(如适用)添加屬性值
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				//通過bw的PropertyDescriptor屬性名,查找出對應的Bean對象,将其添加到newPvs中
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			// 根據自動裝配的類型(如果适用)添加屬性值
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				//通過bw的PropertyDescriptor屬性類型,查找出對應的Bean對象,将其添加到newPvs中
				autowireByType(beanName, mbd, bw, newPvs);
			}
			//讓pvs重新引用newPvs,newPvs此時已經包含了pvs的屬性值以及通過AUTOWIRE_BY_NAME,AUTOWIRE_BY_TYPE自動裝配所得到的屬性值
			pvs = newPvs;
		}
           
  • 調用InstantiationAwareBeanPostProcessor及其子類的postProcessPropertyValues()方法,以針對屬性進行一些操作
//@autoWired注解的注入工作
		if (hasInstAwareBpps) {
			//如果pvs為null
			if (pvs == null) {
				//嘗試擷取mbd的PropertyValues
				pvs = mbd.getPropertyValues();
			}
			//周遊工廠内的所有後置處理器
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				//如果 bp 是 InstantiationAwareBeanPostProcessor 的執行個體
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					//将bp 強轉成 InstantiationAwareBeanPostProcessor 對象
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					//postProcessProperties:在工廠将給定的屬性值應用到給定Bean之前,對它們進行後處理,不需要任何屬性掃描符。該回調方法在未來的版本會被删掉。
					// -- 取而代之的是 postProcessPropertyValues 回調方法。
					// 讓ibp對pvs增加對bw的Bean對象的propertyValue,或編輯pvs的proertyValue
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					//如果pvs為null
					if (pvsToUse == null) {
						//如果filteredPds為null
						if (filteredPds == null) {
							//mbd.allowCaching:是否允許緩存,預設時允許的。緩存除了可以提高效率以外,還可以保證在并發的情況下,傳回的PropertyDesciptor[]永遠都是同一份
							//從bw提取一組經過篩選的PropertyDesciptor,排除忽略的依賴項或忽略項上的定義的屬性
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						//postProcessPropertyValues:一般進行檢查是否所有依賴項都滿足,例如基于"Require"注釋在 bean屬性 setter,
						// 	-- 替換要應用的屬性值,通常是通過基于原始的PropertyValues建立一個新的MutablePropertyValue執行個體, 添加或删除特定的值
						// 	-- 傳回的PropertyValues 将應用于bw包裝的bean執行個體 的實際屬性值(添加PropertyValues執行個體到pvs 或者 設定為null以跳過屬性填充)
						//回到ipd的postProcessPropertyValues方法
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						//如果pvsToUse為null,将終止該方法精緻,以跳過屬性填充
						if (pvsToUse == null) {
							return;
						}
					}
					//讓pvs引用pvsToUse
					pvs = pvsToUse;
				}
			}
		}
           

要注意的是,以上步驟,除了InstantiationAwareBeanPostProcessor及其子類的内部實作邏輯我們不得而知。其他的方式都沒有進行屬性的指派,隻是尋找需要注入的屬性,并将屬性和值儲存到PropertyValues對象中。

  • 最後将PropertyValues中的鍵值對進行屬性注入操作
//如果pvs不為null
		if (pvs != null) {
			//應用給定的屬性值,解決任何在這個bean工廠運作時其他bean的引用。必須使用深拷貝,是以我們 不會永久地修改這個屬性
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
           

最後,附上流程圖

Spring源碼學習第十一天==>填充Bean屬性