Spring 原始碼閱讀 42:AutowiredAnnotationBeanPostProcessor 分析(3)

語言: CN / TW / HK

持續創作,加速成長!這是我參與「掘金日新計劃 · 10 月更文挑戰」的第13天,點選檢視活動詳情

基於 Spring Framework v5.2.6.RELEASE

接上篇:Spring 原始碼閱讀 41:AutowiredAnnotationBeanPostProcessor 分析(2)

概述

前兩篇文章分析了 AutowiredAnnotationBeanPostProcessor 後處理器的 determineCandidateConstructorspostProcessMergedBeanDefinition方法,本文分析最後一個關鍵的方法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)

接下來,呼叫了metadatainject方法,並在最後將引數重傳入的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 型別中找到的所有被標記了屬性注入註解的非靜態的屬性和方法。checkedElementsinjectedElements中被註冊到相應的 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 後處理器的原始碼分析就結束了。