首頁 > 軟體

Spring原始碼解析後置處理器梳理總結

2022-07-07 14:04:13

前言

在前面幾篇文章中梳理了Spring中bean的建立過程,在這個過程中各式各樣的後置處理器發揮了不同的作用,可以說後置處理器貫穿了bean的範例化以及初始化過程。在這篇文章中,將按照出場順序對後置處理器作用場景及發揮功能進行梳理。

1、InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation()方法

AbstractAutowireCapableBeanFactory 的createBean方法中呼叫,這時bean還沒有被範例化:

呼叫resolveBeforeInstantiation方法:

applyBeanPostProcessorsBeforeInstantiation方法:

在這裡,首先拿到spring中提供的所有後置處理器,判斷是不是InstantiationAwareBeanPostProcessor。該後置處理器實現了BeanPostProcessor,在這呼叫了postProcessBeforeInstantiation方法。

這裡在目標物件被spring範例化之前呼叫,postProcessBeforeInstantiation方法的返回值型別是Object,可以返回任何型別的值。由於此時目標物件還未範例化,所以這個返回值可以用來代替原本該生成的目標物件的範例,一般為代理物件。

如果該方法的返回的Object物件代替了原本該生成的目標物件,那麼就會把返回的物件放到單例池當中快取,後續只有BeanPostProcessorpostProcessAfterInitialization方法會呼叫,其它方法不再呼叫。

如果這裡返回了null,就按照正常的流程建立物件,交給spring去負責物件的範例化。因此這個方法可以判斷這個物件在spring範例化之前是否要做特殊的處理,比如不交給Spring管理,自己使用代理產生。

2、SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors()方法

AbstractAutowireCapableBeanFactory 的createBeanInstance方法中呼叫:

determineConstructorsFromBeanPostProcessors方法,該方法用於推斷範例化的構造方法,這裡可能檢測出bean擁有多個候選構造方法:

SmartInstantiationAwareBeanPostProcessor介面的實現類AutowiredAnnotationBeanPostProcessor負責完成這個過程,如果有多個構造方法的情況下,ctors會返回空,後續使用預設無參構造方法進行範例化。但是如果有一個構造方法上有@Autowired註解,spring會優先選擇這個方法。

3、MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition()方法

AbstractAutowireCapableBeanFactorydoCreateBean方法中呼叫:

applyMergedBeanDefinitionPostProcessors方法:

在方法中對所有實現了MergedBeanDefinitionPostProcessor介面的後置處理器進行遍歷,這裡具體呼叫AutowiredAnnotationBeanPostProcessor,用於掃描需要注入的屬性。

AutowiredAnnotationBeanPostProcessor中,定義了兩種需要掃描的註解型別,@Autowired@Value

findAutowiredAnnotation方法中:

對正在建立的bean進行掃描,如果有屬性和方法上面加了這兩個註解,就會把對應的方法或者屬性儲存,最終在buildAutowiringMetadata方法中封裝成InjectionMetadata物件。

需要注意這裡的後置處理器僅僅用於掃描及快取bean的注入資訊,這裡只完成了查詢功能,沒有完成屬性的注入,屬性的注入是在之後的另外的後置處理器中完成的。

4、SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference()方法

AbstractAutowireCapableBeanFactorydoCreateBean 方法中呼叫,主要用於處理Bean的迴圈依賴:

在產生迴圈依賴後呼叫getEarlyBeanReference方法:

在這裡遍歷後置處理器,得到經過後置處理器代理後的物件,放入spring的二級快取當中,提前暴露供迴圈參照的情況呼叫。注意這裡返回的僅僅是一個物件,還算不上是一個完整的bean物件。這個具體呼叫過程在上一篇講迴圈依賴的中的文章中講的比較詳細,如果有不明白的可以回顧一下。

5、InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation()方法

AbstractAutowireCapableBeanFactorypopulateBean方法中呼叫:

populateBean方法中:

該方法在目標物件範例化之後呼叫,這個時候物件已經被範例化,但是該範例的屬性還未被設定,都是null

這裡遍歷後置處理器,如果實現了InstantiationAwareBeanPostProcessor,那麼就呼叫postProcessAfterInstantiation方法。如果方法返回值為true,按照正常流程進行屬性值的填充;如果該方法返回false,會忽略屬性值的設定過程。簡而言之,該後置處理器用於判斷當前範例化完成的bean需不需要進行屬性填充。

6、InstantiationAwareBeanPostProcessor的postProcessPropertyValues()方法

同樣在populateBean方法中,在postProcessAfterInstantiation後返回true時執行,如果方法返回false,該方法不會被呼叫。

遍歷後置處理器,如果屬於InstantiationAwareBeanPostProcessor型別,則呼叫它的postProcessPropertyValues方法。

這裡發揮作用的是AutowiredAnnotationBeanPostProcessor,負責對新增了 @Autowired@Value等註解的屬性進行依賴的填充。在其中遍歷所有需要注入的屬性的列表,使用反射將注入的bean範例賦值給屬性。(具體過程參照Spring範例化Bean原始碼解析)

7、BeanPostProcessor的postProcessBeforeInitialization()方法

AbstractAutowireCapableBeanFactory的doCreateBean方法中呼叫initializeBeanfan方法:

applyBeanPostProcessorsBeforeInitialization方法中:

在該方法中,遍歷執行所有BeanPostProcessorpostProcessBeforeInitialization方法。

在執行該方法前,bean已經被範例化完成,並且完成了屬性的填充,因此這個過程屬於後續的bean的初始化過程。

需要注意的是,如果在bean中有方法被標註了@PostContrust註解,那麼在CommonAnnotationBeanPostProcessor中,會呼叫該@PostContrust方法。

8、BeanPostProcessor的postProcessAfterInitialization()方法

和第7次呼叫入口相同,也是在AbstractAutowireCapableBeanFactoryinitializeBean方法中:

applyBeanPostProcessorsAfterInitialization方法中:

遍歷執行所有BeanPostProcessorpostProcessAfterInitialization方法。綜上所述,bean的各種方法執行屬性為,先執行構造方法,再執行後置管理器中的before方法及@PostContrust方法,最後執行後置處理器的after方法。

9、InitDestroyAnnotationBeanPostProcessor的postProcessBeforeDestruction()方法

如果當前bean中有方法被@PreDestroy註解標註,那麼當Spring的ApplicationContext執行close方法時呼叫該後置處理器。在DefaultSingletonBeanRegistry中執行destroyBean方法:

呼叫destroy方法:

InitDestroyAnnotationBeanPostProcessorpostProcessBeforeDestruction方法:

在該方法中,呼叫@PreDestroy註解標註的方法,執行銷燬方法。

總結

本文對貫穿bean的範例化及初始化過程中出現的後置處理器進行了一下梳理,但是還有很多其他的後置處理器沒有講到。可以說後置處理器是spring提供給使用者的一些擴充套件點,如果能夠熟練的使用這些後置處理器,能夠幫助我們接觸到一些spring中比較深層的東西,並對spring中的生命週期進行有利的插手。


IT145.com E-mail:sddin#qq.com