Spring 原始碼閱讀 42:AutowiredAnnotationBeanPostProcessor 分析(3)
持續創作,加速成長!這是我參與「掘金日新計劃 · 10 月更文挑戰」的第13天,點選檢視活動詳情
基於 Spring Framework v5.2.6.RELEASE
接上篇:Spring 原始碼閱讀 41:AutowiredAnnotationBeanPostProcessor 分析(2)
概述
前兩篇文章分析了 AutowiredAnnotationBeanPostProcessor 後處理器的 determineCandidateConstructors
和postProcessMergedBeanDefinition
方法,本文分析最後一個關鍵的方法postProcessProperties
。
本文的內容非常依賴上一篇文章中的內容,因此強烈建議先閱讀之前的文章。
postProcessProperties
方法的呼叫時機,是在早期 Bean 例項被建立之後、執行屬性注入之前,此時,通過呼叫postProcessProperties
方法,可以對即將注入的屬性和屬性值做一些處理。
postProcessProperties
方法
進入postProcessProperties
方法的原始碼。
// org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
首先,通過findAutowiringMetadata方法獲取注入元資訊,這個方法在上一篇做過詳細的介紹,而且,上一篇介紹的postProcessMergedBeanDefinition
在此時已經被呼叫過了,所以,這裡可以直接從快取中獲取到注入元資訊。
關於注入元資訊metadata
中的詳細內容,也可以參考上一篇文章,這裡就不錯做介紹了。
上一篇傳送門:Spring 原始碼閱讀 41:AutowiredAnnotationBeanPostProcessor 分析(2)
接下來,呼叫了metadata
的inject
方法,並在最後將引數重傳入的pvs作為方法的返回值返回。所以,這裡的inject
是處理邏輯的關鍵方法,而被處理的物件就是pvs
,也就是要給 Bean 例項注入屬性的屬性值。
InjectionMetadata 的inject
方法
我們進入inject
方法。
// org.springframework.beans.factory.annotation.InjectionMetadata#inject
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
}
在inject
方法中,首先聲明瞭一個elementsToIterate
變數,如果當前元資訊物件的checkedElements
成員變數不是空,那麼elementsToIterate
的值就是checkedElements
,如果是空,則這個值是injectedElements
。
此處的兩個集合,依然需要參考上一篇文章中介紹過的內容,這裡做簡單的回顧。injectedElements
指的是 Spring 從當前處理的 Bean 型別中找到的所有被標記了屬性注入註解的非靜態的屬性和方法。checkedElements
是injectedElements
中被註冊到相應的 BeanDefinition 的externallyManagedConfigMembers
中的元素。
有了要處理的資料之後,如果elementsToIterate
不為空,則遍歷其中的每一個 InjectedElement 物件,進行處理。處理的邏輯在 InjectedElement 的inject
方法中。
InjectedElement 的inject
方法
進入inject
方法。
``` // org.springframework.beans.factory.annotation.InjectionMetadata.InjectedElement#inject protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable {
if (this.isField) { Field field = (Field) this.member; ReflectionUtils.makeAccessible(field); field.set(target, getResourceToInject(target, requestingBeanName)); } else { if (checkPropertySkipping(pvs)) { return; } try { Method method = (Method) this.member; ReflectionUtils.makeAccessible(method); method.invoke(target, getResourceToInject(target, requestingBeanName)); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } } ```
因為每一個 InjectedElement 物件都是一個屬性或者方法,這裡將需要注入值的屬性和方法分開處理。
如果是一個屬性,則獲取到對應的 Field 物件,呼叫field.set
設定屬性;如果是一個方法,則將要設定的屬性值作為引數呼叫method.invoke
執行這個方法。這樣,屬性注入就完成了。
在上面的方法中,不管是屬性還是方法,在注入值的時候,都會通過getResourceToInject方法獲取要注入的值,這個方法其實就是從 BeanFactory 容器中查詢對應的 Bean 例項物件。
總結
本文介紹了 AutowiredAnnotationBeanPostProcessor 的postProcessProperties
方法的原始碼,分析了 Spring 是如何查詢通過註解注入的屬性值的。至此,AutowiredAnnotationBeanPostProcessor 後處理器的原始碼分析就結束了。
- Spring 原始碼閱讀 42:AutowiredAnnotationBeanPostProcessor 分析(3)
- Spring 原始碼閱讀 41:AutowiredAnnotationBeanPostProcessor 分析(2)
- Kafka 消費者組 Rebalance 詳細過程
- Spring 原始碼閱讀 01:Resource 資源抽象
- 初識機器學習:迴歸分析
- 初識機器學習:Louvain 社群發現演算法
- 初識機器學習:關聯規則
- 使用 Redis 實現分散式鎖的方法
- Kafka 目錄裡的指令碼那麼多,它們都是用來幹什麼的?
- Kafka 消費者組位移重設的幾種方式
- LeetCode - 84. 柱狀圖中最大的矩形
- LeetCode - 22. 括號生成