Spring Bean 的一生

WindWant發表於2024-04-01

Spring Bean 的一生包括其從建立到消亡的整個過程:

例項建立 => 填充 => 初始化 => 使用 => 銷燬。

這裡需要注意的是,從 bean 例項的建立到可以使用之間還包括【填充】和【初始化】兩個步驟。

AbstractAutowireCapableBeanFactory::createBean:bean 建立核心方法,包含建立、填充 bean 例項及應用 post-processors 等邏輯。

一、例項建立

1、例項化前置處理

InstantiationAwareBeanPostProcessor 為 BeanPostProcessor 子介面,用以提供【建立例項】前後回撥處理。

如果有實現 InstantiationAwareBeanPostProcessor 介面,則應用此介面,返回結果如果不為 null,則直接返回作為 bean 例項。

2、doCreateBean

實際用於執行 bean 建立的方法,所有的建立、填充、初始化、註冊銷燬等邏輯都在此處處理。

BeanWrapper:Spring 底層 JavaBean 結構核心介面,提供了分析和管理 JavaBean 的相關操作。不直接使用,通常隱式的透過 BeanFactory 或者 DataBinder 來使用。此處執行邏輯即為使用 BeanWrapper 物件。

factoryBeanInstanceCache:儲存 FactoryBean name --> BeanWrapper 鍵值對映。執行例項建立伊始,會先從 factoryBeanInstanceCache 查詢獲取,存在則直接獲取(獲取後刪除)使用。

好吧,這裡有個問題,為什麼會有個 factoryBeanInstanceCache 快取?

源頭在於對單例 FactoryBean 型別操作,getSingletonFactoryBeanForTypeCheck。

建立 bean 例項 createBeanInstance:

優先順序順序:

  • 透過 InstanceSupplier 建立(5.0以後)

  • 透過工廠方法建立

  • 建構函式建立

至此,bean 例項已建立完畢。

此處還有一個 post-processor 處理:MergedBeanDefinitionPostProcessor,用於 bean 定義修改(只針對 RootBeanDefinition:merge 了多個來源 BeanDefinition 的執行時檢視)。

3、單例例項提前暴露

為了解決單例迴圈依賴問題,提前將未完全建立好的單例例項快取起來。

這裡說的未完全建立好是指還不能正常使用。

earlySingletonExposure 條件:

  • 單例:scope 為 “singleton” 或者 ”“。

  • 允許自動處理迴圈依賴:allowCircularReferences 預設 true

  • 單例 bean 處於建立中:DefaultSingletonBeanRegistry:singletonsCurrentlyInCreation 儲存所有處於建立中的 bean 名稱。

addSingletonFactory:

將 singletonFactory 新增到 singletonFactories 快取中,以備解決迴圈依賴使用。

singletonFactories 是什麼呢?

字面意思為單例工廠快取(bean name -> ObjectFactory ):即所謂的第三級快取,儲存目標 bean 所對應的 bean 工廠物件鍵值。

那 ObjectFactory 這個物件是怎麼獲取的呢?

SmartInstantiationAwareBeanPostProcessor::getEarlyBeanReference

SmartInstantiationAwareBeanPostProcessor 是 InstantiationAwareBeanPostProcessor 的擴充套件介面。

InstantiationAwareBeanPostProcessor 我們說過,是作用在建立例項前後。此處為建立例項後情景。

ObjectFactory 雖名為工廠,其實際為用以在 bean 建立早期,訪問相應 bean 的一個引用。

什麼是早期呢?

就是這會兒,剛建立完例項,還沒有進行相應的填充、初始化等後續操作。

那為什麼是暴露個引用,而不是直接給出目標物件呢?

因為目標 bean 可能還會經過其它 post-processors 處理。像 AbstractAutoProxyCreator::getEarlyBeanReference 中的代理邏輯處理。

二、填充

屬性填充,作用於 AbstractAutowireCapableBeanFactory::populateBean。

1、屬性填充前置處理

continueWithPropertyPopulation:是否繼續處理屬性填充判斷。

這裡的說明是在執行屬性填充前給予任何 InstantiationAwareBeanPostProcessors 一個機會來變更 bean 的狀態。

什麼意思呢?

就是 InstantiationAwareBeanPostProcessors 的 postProcessAfterInstantiation 處理,對目標 bean 做相應的變更。

做什麼變更呢?

這個節點在 Spring 自動注入操作之前,可以執行個性化的屬性注入。同時,方法返回值會賦予 continueWithPropertyPopulation,以決定是否執行後續的邏輯。

這裡有一個點需要注意:

如果當前 InstantiationAwareBeanPostProcessors::postProcessAfterInstantiation 返回 false,那麼 bean 屬性填充步驟則就此終止,不會再執行其它的 InstantiationAwareBeanPostProcessors 及後續的 Spring bean 屬性填充過程。

2、屬性填充

MutablePropertyValues

PropertyValues 介面的一個實現,提供對屬性的各種操作,同時提供相應的建構函式來支援深度複製及基於 Map 的構造。

自動注入方式:按順序 BY_NAME => BY_TYPE

BY_NAME

autowireByName 根據名稱填充

填充什麼呢?

unsatisfiedNonSimpleProperties。

什麼是 unsatisfiedNonSimpleProperties 呢?

  • 可寫的:即擁有寫方法。

  • 需要依賴檢查的:基於 ignoredDependencyTypes 屬性設定判斷。

  • 非本身型別的。

  • 非簡單型別屬性的:屬性本身型別及陣列元素型別為非簡單型別。包括(基本型別及其包裝型別,如 int、Integer 等)

注入:

首先根據屬性名稱判斷 bean 存在:
即是否包含在 bean 工廠及外部註冊單例 bean。

  • alias 的,會做相應的名稱轉換。

  • 存在繼承關係的,會級聯向上查詢。

根據屬性名稱獲取 bean:AbstractBeanFactory::getBean。

屬性設定。

註冊 bean 依賴:dependentBeanMap beanName -> Set<BeanName>,即記錄 bean 及其依賴 bean 關係。

BY_TYPE

autowireByName 根據型別填充。

一個 BeanFactory 裡必須恰好只有一個匹配需要型別。

同樣,首先獲取需要填充的屬性:unsatisfiedNonSimpleProperties。

排除 Object 型別屬性,填充沒有意義。

處理依賴。

屬性設定

註冊 bean 依賴。

3、依賴檢查

依賴檢查分為兩部分:一個基於 InstantiationAwareBeanPostProcessor::postProcessPropertyValues 處理。一個基於 AbstractBeanDefinition::dependencyCheck 處理。

InstantiationAwareBeanPostProcessor:

對特定的屬性進行依賴檢查及處理;對特定屬性值進行替換,新增或者刪除。

如 RequiredAnnotationBeanPostProcessor、 AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、MockitoPostProcessor等。

dependencyCheck

檢查所有暴露的屬性是否都已賦值。

4、屬性賦值

將上述處理過的屬性值填充到 bean 例項。

三、初始化

應用工廠回撥,定義的初始化方法及post-processors。

1、Aware 處理

Aware 代表了各種各樣的資源,處理 Aware 即為將相應的資源新增到 bean 例項中。

如 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 等。

2、BeanPostProcessorsBeforeInitialization

顧名思義,這裡的 BeanPostProcessors 是初始化之前的處理。

如 AbstractAdvisingBeanPostProcessor 檢查。

3、執行初始化方法

a)實現了 InitializingBean 介面的 bean,執行相應的 afterPropertiesSet 方法。

b)定義了 initMethod 的,觸發相應的方法呼叫。

兩者是否可以同時存在呢?

可以,如果同時存在,但是初始化方法名稱不能為 afterPropertiesSet。執行順序為先 a 後 b。

4、BeanPostProcessorsAfterInitialization

同 2,此處為初始化之後的處理。

如 BeanValidationPostProcessor、ApplicationListenerDetector 等。

其實很多 PostProcessor 是既有 Before 處理邏輯,亦有 After 處理邏輯的,此處不再贅述。

四、disposable bean 註冊

bean 工廠維護了一個 disposable bean 列表(bean name --> disposable instance)。在工廠關閉銷燬時,同時銷燬相應的 bean 例項物件。

定義銷燬可以透過實現 DisposableBean 或者 AutoCloseable 介面或者自定義銷燬方法。

如果使用一個定義了相應銷燬方法的物件,又不想其執行銷燬方法時怎麼辦呢?
註解或者配置其銷燬方法為空,如:@Bean(destroyMethod = "")。

DestructionAwareBeanPostProcessor:例項銷燬前,使用者可以自定義執行特定的操作。如:ApplicationListenerDetector 移除相應的 Listener;ScheduledAnnotationBeanPostProcessor 移除定時任務等。

相關文章