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 後處理器的源碼分析就結束了。