死磕Spring之IoC篇 - Bean 的屬性填充階段


該系列文章是本人在學習 Spring 的過程中總結下來的,里面涉及到相關源碼,可能對讀者不太友好,請結合我的源碼注釋 Spring 源碼分析 GitHub 地址 進行閱讀

Spring 版本:5.1.14.RELEASE

開始閱讀這一系列文章之前,建議先查看《深入了解 Spring IoC(面試題)》這一篇文章

該系列其他文章請查看:《死磕 Spring 之 IoC 篇 - 文章導讀》

Bean 的屬性填充階段

當我們顯示或者隱式地調用AbstractBeanFactorygetBean(...) 方法時,會觸發 Bean 的加載,在《開啟 Bean 的加載》文章中分析了整個加載過程。

對於不同作用域的 Bean,底層都會調用 AbstractAutowireCapableBeanFactorycreateBean(...) 方法進行創建,在《Bean 的創建過程》文章中分析了整個創建過程。創建 Bean 的過程中,在獲取到的一個實例對象后,里面的相關屬性也許是空的,那么接下來要做的就是將需要填充的屬性進行依賴注入,然后再進行后續的初始化工作。整個的屬性填充過程非常復雜,因為配置的屬性值可能是一個表達式,需要解析,類型也可能不對,需要進行類型轉換,還可能是一個對象,需要找到對應的 Bean 然后注入(依賴注入),存在有各種處理,本文將會分析創建 Bean 過程中的屬性填充階段。

回顧

先來回顧一下創建 Bean 過程中屬性填充階段對應的代碼:

// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// Initialize the bean instance.
// 開始初始化 `bean`
Object exposedObject = bean;
try {
    // <4> 對 `bean` 進行屬性填充,注入對應的屬性值
    populateBean(beanName, mbd, instanceWrapper);
    // <5> 初始化這個 `exposedObject`,調用其初始化方法
    exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
    if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
        throw (BeanCreationException) ex;
    }
    else {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
    }
}

在創建好實例對象后,這個對象的屬性還沒有賦值,所以將這個實例對象的相關屬性進行賦值,也就是上面的第 <4>

開啟 Bean 的屬性填充

populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) 方法,屬性填充,如下:

// AbstractAutowireCapableBeanFactory.java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    // <1> 如果實例對象為空,則進行下面的判斷
    if (bw == null) {
        // <1.1> 這個 Bean 有屬性,則拋出異常
        if (mbd.hasPropertyValues()) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
        }
        // <1.2> 否則,不用屬性填充,直接 `return`
        else {
            // Skip property population phase for null instance.
            return;
        }
    }

    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    // state of the bean before properties are set. This can be used, for example,
    // to support styles of field injection.
    // <2> 實例化階段的后置處理,如果滿足這兩個條件
    if (!mbd.isSynthetic() // RootBeanDefinition 不是用戶定義的(由 Spring 解析出來的)
            && hasInstantiationAwareBeanPostProcessors()) { // 是否有 InstantiationAwareBeanPostProcessor 處理器
        // <2.1> 遍歷所有的 BeanPostProcessor
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            // 如果為 InstantiationAwareBeanPostProcessor 類型
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                // <2.2> 對實例化對象進行后置處理
                // 注意如果返回 false,直接 `return`,不會調用后面的 InstantiationAwareBeanPostProcessor 處理器,也不會進行接下來的屬性填充
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    return;
                }
            }
        }
    }

    // <3> 獲取 `pvs`,承載當前對象的屬性值
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

    // <4> 獲取這個 Bean 的注入模式,默認為 **AUTOWIRE_NO**,例如可以通過 `@Bean` 注解的 `autowire` 屬性配置注入模式
    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    // <4.1> 如果注入模式為 **AUTOWIRE_BY_NAME** 或者 **AUTOWIRE_BY_TYPE**,則通過下面的方式獲取屬性值
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
        // <4.2> 將 `pvs` 封裝成 MutablePropertyValues 對象 `newPvs`(允許對屬性進行相關操作)
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // Add property values based on autowire by name if applicable.
        // <4.3> **AUTOWIRE_BY_NAME** 模式,通過名稱獲取相關屬性值,保存在 `newPvs` 中
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // Add property values based on autowire by type if applicable.
        // <4.4> **AUTOWIRE_BY_TYPE** 模式,通過類型獲取相關屬性值,保存在 `newPvs` 中
        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        // <4.5> 將 `newPvs` 復制給 `pvs`
        pvs = newPvs;
    }

    // 是否有 InstantiationAwareBeanPostProcessor 處理器
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    // 是否需要進行依賴檢查,默認為 true
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

    PropertyDescriptor[] filteredPds = null;
    // <5> 通過 InstantiationAwareBeanPostProcessor 處理器(如果有)對 `pvs` 進行處理
    if (hasInstAwareBpps) {
        if (pvs == null) {
            pvs = mbd.getPropertyValues();
        }

        // <5.1> 遍歷所有的 BeanPostProcessor
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            // 如果為 InstantiationAwareBeanPostProcessor 類型
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                /**
                 * Spring 內部的 InstantiationAwareBeanPostProcessor 處理器:
                 * {@link AutowiredAnnotationBeanPostProcessor#postProcessProperties} 會解析 @Autowired 和 @Value 注解標注的屬性,獲取對應屬性值;
                 * {@link org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessProperties} 會解析 @Resource 注解標注的屬性,獲取對應的屬性值
                 */
                // <5.2> 調用處理器的 `postProcessProperties(...)` 方法,對 `pvs` 進行后置處理
                PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                // <5.3> 如果上一步的處理結果為空,可能是新版本導致的(Spring 5.1 之前沒有上面這個方法),則需要兼容老版本
                if (pvsToUse == null) {
                    // <5.3.1> 找到這個 Bean 的所有 `java.beans.PropertyDescriptor` 屬性描述器(包含這個屬性的所有信息)
                    if (filteredPds == null) {
                        filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                    }
                    // <5.3.2> 調用處理器的 `postProcessPropertyValues(...)` 方法,對 `pvs` 進行后置處理
                    pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    // <5.3.3> 如果處理后的 PropertyValues 對象為空,直接 `return`,則不會調用后面的 InstantiationAwareBeanPostProcessor 處理器,也不會進行接下來的屬性填充
                    if (pvsToUse == null) {
                        return;
                    }
                }
                // <5.4> 將處理后的 `pvsToUse` 復制給 `pvs`
                pvs = pvsToUse;
            }
        }
    }
    // <6> 依賴檢查
    if (needsDepCheck) {
        // <6.1> 找到這個 Bean 的所有 `java.beans.PropertyDescriptor` 屬性描述器(包含這個屬性的所有信息)
        if (filteredPds == null) {
            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        }
        // <6.2> 依賴檢查,如果沒有找到對應的屬性值,則根據檢查策略進行拋出異常(默認不會)
        checkDependencies(beanName, mbd, filteredPds, pvs);
    }

    // <7> 如果 `pvs` 不為空,則將里面的屬性值設置到當前 Bean 對應的屬性中(依賴注入)
    // 前面找到的屬性值並沒有設置到 Bean 中,且屬性值可能是一個表達式,類型也可能也不對,需要先進行處理和類型轉換,然后再設置到該實例對象中
    if (pvs != null) {
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

過程大致如下:

  1. 如果實例對象為null,則進行下面的判斷

    1. 這個 Bean 有屬性,則拋出異常
    2. 否則,不用屬性填充,直接 return
  2. 實例化階段的后置處理,如果滿足這兩個條件:RootBeanDefinition 不是用戶定義的(由 Spring 解析出來的)、是否有 InstantiationAwareBeanPostProcessor 處理器

    1. 遍歷所有的 BeanPostProcessor

    2. 如果為 InstantiationAwareBeanPostProcessor 類型,則對實例化對象進行后置處理

      注意,如果返回 false,直接 return,不會調用后面的 InstantiationAwareBeanPostProcessor 處理器,也不會進行接下來的屬性填充

  3. 獲取 pvs,承載當前對象的屬性值

  4. 獲取這個 Bean 的注入模式,默認為 AUTOWIRE_NO,例如可以通過 @Bean 注解的 autowire 屬性配置注入模式

    1. 如果注入模式為 AUTOWIRE_BY_NAME 或者 AUTOWIRE_BY_TYPE,則通過下面的方式獲取屬性值
    2. pvs 封裝成 MutablePropertyValues 對象 newPvs(允許對屬性進行相關操作)
    3. AUTOWIRE_BY_NAME 模式,通過名稱獲取相關屬性值,保存在 newPvs 中,調用 autowireByName(...) 方法
    4. AUTOWIRE_BY_TYPE 模式,通過類型獲取相關屬性值,保存在 newPvs 中,調用 autowireByType(...) 方法
    5. newPvs 復制給 pvs
  5. 通過 InstantiationAwareBeanPostProcessor 處理器(如果有)對 pvs 進行處理

    1. 遍歷所有的 BeanPostProcessor
    2. 如果為 InstantiationAwareBeanPostProcessor 類型,則調用其 postProcessProperties(...) 方法,對 pvs 進行后置處理
    3. 如果上一步的處理結果為空,可能是新版本導致的(Spring 5.1 之前沒有上面這個方法),則需要兼容老版本
      1. 嘗試找到這個 Bean 的所有 java.beans.PropertyDescriptor 屬性描述器(包含這個屬性的所有信息)
      2. 調用處理器的 postProcessPropertyValues(...) 方法,對 pvs 進行后置處理
      3. 如果處理后的 PropertyValues 對象為空,直接 return,則不會調用后面的處理器,也不會進行接下來的屬性填充
    4. 將處理后的 pvsToUse 復制給 pvs
  6. 依賴檢查

    1. 找到這個 Bean 的所有 java.beans.PropertyDescriptor 屬性描述器(包含這個屬性的所有信息)
    2. 進行依賴檢查,如果沒有找到對應的屬性值,則根據檢查策略進行拋出異常(默認不會)
  7. 如果 pvs 不為空,則將里面的屬性值設置到當前 Bean 對應的屬性中(依賴注入),調用 applyPropertyValues(...) 方法

    前面找到的屬性值並沒有設置到 Bean 中,且屬性值可能是一個表達式,類型也可能也不對,需要先進行處理和類型轉換,然后再設置到該實例對象中


整個的屬性填充過程非常的復雜,接下來進行概括:

  • 允許你對實例化對象進行后置處理,處理結果為 false 表示不需要進行接下來的屬性填充過程
  • 根據注入模式,找到沒有配置屬性值的對象屬性,然后找到對應的 Bean,默認注入模式為不注入
  • 允許你對屬性值進行后置處理,例如 @Autowired@Value 等注解標注的屬性會通過這里找到對應的屬性值(或對象)
  • 上述過程僅找到了屬性值,還沒設置到當前實例對象中,所以最后一步才是真正的屬性填充

上面有兩種注入模式:AUTOWIRE_BY_NAMEAUTOWIRE_BY_TYPE,默認為 AUTOWIRE_NO,接下來先來看看這兩種注入模式的實現

通過名稱獲取屬性值

autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) 方法,通過名稱獲取相關屬性值,如下:

// AbstractAutowireCapableBeanFactory.java
protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

    // <1> 獲取當前 Bean 中不滿意的非簡單類型的屬性名稱,也就是沒有定義屬性值的"對象"屬性
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    // <2> 遍歷這些對象屬性的名稱
    for (String propertyName : propertyNames) {
        // <3> 如果當前容器存在對應的 Bean(通過名稱判斷)
        if (containsBean(propertyName)) {
            // <3.1> 根據屬性名稱獲取對應的 `bean` 對象(依賴查找)
            Object bean = getBean(propertyName);
            // <3.2> 將 `bean` 添加至 `pvs`
            pvs.add(propertyName, bean);
            // <3.3> 將兩個 Bean 之間的依賴關系保存起來
            registerDependentBean(propertyName, beanName);
            if (logger.isTraceEnabled()) {
                logger.trace("Added autowiring by name from bean name '" + beanName +
                        "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
            }
        } else {
            if (logger.isTraceEnabled()) {
                logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
                        "' by name: no matching bean found");
            }
        }
    }
}

過程並不復雜,大致如下:

  1. 獲取當前 Bean 中不滿意的非簡單類型的屬性名稱,也就是沒有定義屬性值的"對象"屬性,如下:

    // AbstractAutowireCapableBeanFactory.java
    protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
        Set<String> result = new TreeSet<>();
        // 獲取已設置的屬性值
        PropertyValues pvs = mbd.getPropertyValues();
        // 找到這個 Bean 的所有 PropertyDescriptor 屬性描述器(包含這個屬性的所有信息)
        PropertyDescriptor[] pds = bw.getPropertyDescriptors();
        // 遍歷所有屬性
        for (PropertyDescriptor pd : pds) {
            if (pd.getWriteMethod() != null // 有可寫方法
                    && !isExcludedFromDependencyCheck(pd) // 不忽略
                    && !pvs.contains(pd.getName()) // 沒有對應的屬性值
                    && !BeanUtils.isSimpleProperty(pd.getPropertyType())) // 不是簡單類型(例如一個實體類)
            {
                result.add(pd.getName());
            }
        }
        // 返回這些不滿意的非簡單類型的屬性
        return StringUtils.toStringArray(result);
    }
    
  2. 遍歷這些對象屬性的名稱

  3. 如果當前容器存在對應的 Bean(通過名稱判斷)

    1. 根據屬性名稱獲取對應的 bean 對象(依賴查找
    2. bean 添加至 pvs
    3. 將兩個 Bean 之間的依賴關系保存起來

直接根據"對象"名稱通過 getBean(String beanName) 獲取到對應的對象(依賴查找

通過類型獲取屬性值

autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) 方法,通過類型獲取相關屬性值,如下:

// AbstractAutowireCapableBeanFactory.java
protected void autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

    // <1> 獲取 TypeConverter 類型轉換器,用於取代默認的 PropertyEditor 類型轉換器
    // 例如 Spring 3.0 之后的 ConversionService
    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
        converter = bw;
    }

    Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
    // <2> 獲取當前 Bean 中不滿意的非簡單類型的屬性名稱,也就是沒有定義屬性值的"對象"屬性
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    // <3> 遍歷這些對象屬性的名稱
    for (String propertyName : propertyNames) {
        try {
            // <3> 獲取這個屬性的 `java.beans.PropertyDescriptor` 屬性描述器(包含這個屬性的所有信息)
            PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
            // <4> 如果不是 Object 類型(對 Object 類類型的 Bean 進行自動裝配毫無意義),則嘗試找到對應的對象
            if (Object.class != pd.getPropertyType()) {
                // <5> 找到這個屬性的寫方法
                MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
                // Do not allow eager init for type matching in case of a prioritized post-processor.
                // 是否可以提前初始化
                boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
                // <6> 創建對應的依賴注入描述對象
                DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
                // <7> 依賴注入,找到該屬性對應的對象
                Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
                // <8> 如果找到屬性對象,則將該其添加至 `pvs`
                if (autowiredArgument != null) {
                    pvs.add(propertyName, autowiredArgument);
                }
                // <9> 將注入的屬性對象和當前 Bean 之前的關系保存起來
                // 因為該屬性可能是一個集合,找到了多個對象,所以這里是一個數組
                for (String autowiredBeanName : autowiredBeanNames) {
                    // 將 `autowiredBeanName` 與 `beanName` 的依賴關系保存
                    registerDependentBean(autowiredBeanName, beanName);
                    if (logger.isTraceEnabled()) {
                        logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
                                propertyName + "' to bean named '" + autowiredBeanName + "'");
                    }
                }
                // 清空 `autowiredBeanName` 數組
                autowiredBeanNames.clear();
            }
        } catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
        }
    }
}

過程大致如下:

  1. 獲取 TypeConverter 類型轉換器,用於取代默認的 PropertyEditor 類型轉換器
  2. 獲取當前 Bean 中不滿意的非簡單類型的屬性名稱,也就是沒有定義屬性值的"對象"屬性,和通過名稱注入的過程一樣
  3. 遍歷這些"對象"屬性的名稱,獲取這個屬性的 java.beans.PropertyDescriptor 屬性描述器(包含這個屬性的所有信息)
  4. 如果不是 Object 類型(對 Object 類類型的 Bean 進行自動裝配毫無意義),則嘗試找到對應的對象
  5. 找到這個屬性的寫方法
  6. 創建對應的 DependencyDescriptor 依賴注入描述對象,默認 required 為 false,表示找不到也沒關系
  7. 依賴注入,找到該屬性對應的對象,調用 resolveDependency(...) 方法
  8. 如果找到屬性對象,則將該其添加至 pvs
  9. 將注入的屬性對象和當前 Bean 之前的關系保存起來

根據"對象"名稱通過 resolveDependency(...) 獲取到對應的對象,該方法就是依賴注入的底層實現,整個過程也非常復雜,所以將這部分內容放在下一篇《@Autowired 等注解的實現原理》文章中

屬性值的后置處理

調用 InstantiationAwareBeanPostProcessor#postProcessProperties 方法,對前面屬性值進行處理

在前面的AUTOWIRE_BY_NAMEAUTOWIRE_BY_TYPE兩種注入模式中,找到的都是普通對象的屬性值,例如 @Autowired、@Value 和 @Resource 注解並沒有被解析,且默認的注入模式還是AUTOWIRE_NO,那這些注解是如何被解析的呢?Spring 內部有下面兩個 InstantiationAwareBeanPostProcessor 處理器:

  • AutowiredAnnotationBeanPostProcessor,解析 @Autowired 和 @Value 注解標注的屬性,獲取對應屬性值
  • CommonAnnotationBeanPostProcessor,會解析 @Resource 注解標注的屬性,獲取對應的屬性值

這里先提一下,具體的實現過程在下一篇《@Autowired 等注解的實現原理》文章中進行分析

屬性填充

applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) 方法,屬性填充

如果獲取到的 pvs 屬性值對象不為空,則將里面的屬性值設置到當前 Bean 對應的屬性中(依賴注入),我們知道前面找到的屬性值並沒有設置到 Bean 中,且屬性值可能是一個表達式,類型也可能也不對,需要先進行處理和類型轉換,然后再設置到該實例對象中,方法如下:

// AbstractAutowireCapableBeanFactory.java
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
    // <1> 沒有相關屬性值,則直接 `return` 返回
    if (pvs.isEmpty()) {
        return;
    }
    if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
        ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
    }

    // ------------------------開始屬性值的轉換與填充------------------------

    MutablePropertyValues mpvs = null;
    // 定義一個 `original` 集合,承載屬性值(未進行轉換)
    List<PropertyValue> original;

    // <2> 如果 `pvs` 是 MutablePropertyValues 類型,則可能已經處理過了
    if (pvs instanceof MutablePropertyValues) {
        mpvs = (MutablePropertyValues) pvs;
        if (mpvs.isConverted()) {
            // Shortcut: use the pre-converted values as-is.
            try {
                // <2.1> 屬性值已經轉換了,則將這些屬性值設置到當前 Bean 中(反射機制),依賴注入的最終實現!!!
                bw.setPropertyValues(mpvs);
                return;
            }
            catch (BeansException ex) {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Error setting property values", ex);
            }
        }
        // <2.2> 沒有轉換過,則獲取所有的屬性值集合
        original = mpvs.getPropertyValueList();
    }
    else {
        // <2.2> 獲取所有的屬性值集合
        original = Arrays.asList(pvs.getPropertyValues());
    }

    // 獲取 TypeConverter 類型轉換器,用於取代默認的 PropertyEditor 類型轉換器
    // 例如 Spring 3.0 之后的 ConversionService
    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
        converter = bw;
    }
    // 獲取對應的解析器
    BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

    // Create a deep copy, resolving any references for values.
    // <3> 定義一個 `deepCopy` 集合,保存轉換后的屬性值
    List<PropertyValue> deepCopy = new ArrayList<>(original.size());
    boolean resolveNecessary = false;
    // <4> 遍歷所有的屬性值,進行轉換(如果有必要)
    for (PropertyValue pv : original) {
        // <4.1> 已經轉換過,則直接添加到 `deepCopy` 中
        if (pv.isConverted()) {
            deepCopy.add(pv);
        }
        // <4.2> 否則,開始進行轉換
        else {
            String propertyName = pv.getName();
            // 轉換之前的屬性值
            Object originalValue = pv.getValue();
            // <4.2.1> 表達式的處理(如果有必要的話),例如你在 XML 配置的屬性值為 `${systenm.user}`,則會解析出對應的值
            Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
            // 轉換之后的屬性值
            Object convertedValue = resolvedValue;
            // 該屬性是否可以轉換
            boolean convertible = bw.isWritableProperty(propertyName) && // 屬性可寫
                    !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName); // 不包含 `.` 和 `[`
            if (convertible) {
                // <4.2.2> 使用類型轉換器轉換屬性值(如果有必要的話)
                convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
            }
            // Possibly store converted value in merged bean definition,
            // in order to avoid re-conversion for every created bean instance.
            if (resolvedValue == originalValue) { // 屬性值沒有轉換過
                if (convertible) {
                    // <4.2.3> 設置轉換后的值,避免上面的各種判斷
                    pv.setConvertedValue(convertedValue);
                }
                // <4.2.4> 添加到 `deepCopy` 中
                deepCopy.add(pv);
            }
            // 屬否則屬性值進行了轉換
            else if (convertible // 可轉換的
                    && originalValue instanceof TypedStringValue // 屬性原始值是字符串類型
                    && !((TypedStringValue) originalValue).isDynamic() // 屬性的原始類型值不是動態生成的字符串
                    && !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) // 屬性的原始值不是集合或者數組類型
            {
                // <4.2.3> 設置轉換后的值,避免上面的各種判斷
                pv.setConvertedValue(convertedValue);
                // <4.2.4> 添加到 `deepCopy` 中
                deepCopy.add(pv);
            }
            // 否則
            else {
                // 這個屬性每次都要處理,不能緩存
                resolveNecessary = true;
                // <4.2.4> 添加到 `deepCopy` 中
                deepCopy.add(new PropertyValue(pv, convertedValue));
            }
        }
    }
    // <5> 如果屬性值不為空,且不需要每次都處理,則設置為已轉換
    if (mpvs != null && !resolveNecessary) {
        mpvs.setConverted();
    }

    // Set our (possibly massaged) deep copy.
    try {
        // <6> 將屬性值設置到當前 Bean 中(反射機制),依賴注入的最終實現!!!
        bw.setPropertyValues(new MutablePropertyValues(deepCopy));
    }
    catch (BeansException ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Error setting property values", ex);
    }
}

過程大致如下:

  1. 沒有相關屬性值,則直接 return 返回

開始屬性值的轉換與填充,先定義一個 original 集合,承載屬性值(未進行轉換)

  1. 如果 pvs 是 MutablePropertyValues 類型,則可能已經處理過了,否則,獲取所有的屬性值集合,放入 original 集合中

    1. 屬性值已經轉換了,則將這些屬性值設置到當前 Bean 中(反射機制),依賴注入的最終實現!!!

      調用 BeanWrapperImpl#setPropertyValues(PropertyValues) 方法

    2. 沒有轉換過,則獲取所有的屬性值集合,放入 original 集合中

  2. 定義一個 deepCopy 集合,保存轉換后的屬性值

  3. 遍歷所有的屬性值,進行轉換(如果有必要)

    1. 已經轉換過,則直接添加到 deepCopy
    2. 否則,開始進行轉換
      1. 表達式的處理(如果有必要的話),例如你在 XML 配置的屬性值為 ${systenm.user},則會解析出對應的值
      2. 使用類型轉換器轉換屬性值(如果有必要的話)
      3. 設置轉換后的值,避免上面的各種判斷
      4. 添加到 deepCopy
  4. 如果屬性值不為空,且不需要每次都處理,則設置為已轉換

  5. 將屬性值設置到當前 Bean 中(反射機制),依賴注入的最終實現!!!

    調用 BeanWrapperImpl#setPropertyValues(PropertyValues) 方法


整個屬性注入過程非常復雜,上面僅列出了關鍵步驟,可以看到最終會調用 BeanWrapperImpl#setPropertyValues(PropertyValues) 方法將屬性值設置到 Bean 中

在 Bean 的實例化階段獲取到的就是一個 BeanWrapperImpl 對象,所以這里調用的就是當前 Bean 的 setPropertyValues(PropertyValues) 方法,該方法的底層借助於 Java Beans 的 java.beans.PropertyDescriptor 屬性描述器,獲取到對應的寫方法,然后通過反射機制設置當前 Bean 的屬性值

總結

當我們顯示或者隱式地調用AbstractBeanFactorygetBean(...) 方法時,會觸發 Bean 的加載,在《開啟 Bean 的加載》文章中分析了整個加載過程。

對於不同作用域的 Bean,底層都會調用 AbstractAutowireCapableBeanFactorycreateBean(...) 方法進行創建,在《Bean 的創建過程》文章中分析了整個創建過程。創建 Bean 的過程中,在獲取到的一個實例對象后,需要獲取相關屬性值,然后注入到 Bean 中,其中獲取屬性值有三種模式:

  • AUTOWIRE_NO,默認,不獲取相關屬性值

  • AUTOWIRE_BY_NAME,通過名稱獲取沒有定義屬性值的"對象"的屬性值,通過 getBean(String beanName) 查找

  • AUTOWIRE_BY_TYPE,通過類型獲取沒有定義屬性值的"對象"的屬性值,依賴注入的方式

默認情況下,獲取到已定義的屬性值后不會通過上面的方式去找屬性值,在后續有一個屬性值的后置處理,會調用所有的 InstantiationAwareBeanPostProcessor 處理器的 postProcessProperties 方法進行處理,例如 Spring 內部有兩個 InstantiationAwareBeanPostProcessor 處理器:

  • AutowiredAnnotationBeanPostProcessor,解析 @Autowired 和 @Value 注解標注的屬性,獲取對應屬性值
  • CommonAnnotationBeanPostProcessor,會解析 @Resource 注解標注的屬性,獲取對應的屬性值

在獲取到所有的屬性值后然后通過反射機制設置到 Bean 中

關於 @Autowired、@Value 和 @Resource 注解的實現原理將在下一篇《@Autowired 等注解的實現原理》文章中進行分析


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM