Spring IoC 屬性賦值階段

前言

本系列全部基於 Spring 5.2.2.BUILD-SNAPSHOT 版本。因為 Spring 整個體系太過於龐大,所以只會進行關鍵部分的源碼解析。

本篇文章主要介紹 Spring IoC 容器中 bean 的屬性賦值階段。

正文

我們在Spring IoC bean 的創建一文中分析創建 bean 實例的主要流程,此時創建出來的 bean 還是個屬性未賦值的實例,在創建完之後會進入 populateBean() 方法,即進入屬性賦值階段。我們簡單回顧一下,上次分析過的 doCreateBean() 方法:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {

    // 實例化 bean
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        // 如果bean的作用域是singleton,則需要移除未完成的FactoryBean實例的快取
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // 通過構造函數反射創建bean的實例,但是屬性並未賦值,見下文詳解
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // 獲取bean的實例
    final Object bean = instanceWrapper.getWrappedInstance(); 
    // 獲取bean的類型
    Class<?> beanType = instanceWrapper.getWrappedClass(); 
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                // BeanDefinition 合併後的回調,見下文詳解
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            } 
            // 省略異常處理...
            mbd.postProcessed = true;
        }
    }

    // bean的作用域是單例 && 允許循環引用 && 當前bean正在創建中
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
    // 如果允許bean提前曝光
    if (earlySingletonExposure) {
        // 將beanName和ObjectFactory形成的key-value對放入singletonFactories快取中
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    Object exposedObject = bean;
    try {
        // 給 bean 的屬性賦值
        populateBean(beanName, mbd, instanceWrapper);
        // 初始化 bean
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    } 
    // 省略部分程式碼
}

屬性賦值

AbstractAutowireCapableBeanFactory#populateBean

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    if (bw == null) {
        if (mbd.hasPropertyValues()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
        } else {
            return;
        }
    }
  
    // 給InstantiationAwareBeanPostProcessors最後一次機會在屬性設置前來改變bean
    // 例如:可以用來支援屬性注入的類型
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                // 這裡會調用bean實例化後的生命周期回調,返回false會跳過下面的屬性賦值階段
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    return;
                }
            }
        }
    }
    // 獲取PropertyValues
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    // 獲取依賴注入類型
    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
  	// 如果依賴注入類型是 byName 或者 byType
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      	// 賦值pvs到可修改的MutablePropertyValues
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // 根據名稱自動注入,見下文詳解
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // 根據類型自動注入,見下文詳解
        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }

    // 是否有註冊InstantiationAwareBeanPostProcessors的實現類
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

    PropertyDescriptor[] filteredPds = null;
    if (hasInstAwareBpps) {
        if (pvs == null) {
            pvs = mbd.getPropertyValues();
        }
        // 遍歷並找到InstantiationAwareBeanPostProcessor的實現類,調用處理屬性值的後置處理方法
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                if (pvsToUse == null) {
                    if (filteredPds == null) {
                        filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                    }
                    pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    // 如果屬性值的後置處理方法返回null,直接返回,不會進行底下的屬性值應用階段
                    if (pvsToUse == null) {
                        return;
                    }
                }
                pvs = pvsToUse;
            }
        }
    }
    if (needsDepCheck) {
        if (filteredPds == null) {
            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        }
        checkDependencies(beanName, mbd, filteredPds, pvs);
    }

    if (pvs != null) {
        // 屬性填充,見下文詳解
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

上面方法首先會調用 bean 的實例化後生命周期回調方法,如果返回 false 會跳過下面的屬性賦值階段。關於 InstantiationAwareBeanPostProcessors 介面在Spring IoC bean 的創建一文中介紹過,這裡不再贅述。接著判斷是否是按 名稱 或者 類型 自動注入屬性並填入 newPvs 中,接著調用 bean 屬性填充前的生命周期回調。屬性填充前生命周期回調方法有兩個 postProcessProperties()postProcessPropertyValues(),第一個是 Spring 5.1 新加的,後面的是老的,已經被標記為過時;首先會調用 postProcessProperties() 如果返回空調用 postProcessPropertyValues(),否則直接使用返回的 PropertyValuespostProcessPropertyValues() 如果返回空會直接跳過屬性填充階段,不為空直接使用返回的 PropertyValues

按照名稱依賴注入

AbstractAutowireCapableBeanFactory#autowireByName

protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    // 尋找bw中需要依賴注入的屬性名稱
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    // 遍歷需要注入的bean
    for (String propertyName : propertyNames) {
        if (containsBean(propertyName)) {
          	// 調用getBean()方法獲取bean
            Object bean = getBean(propertyName);
            // 將需要注入bean的實例加入到pvs
            pvs.add(propertyName, bean);
            // 註冊依賴關係
            registerDependentBean(propertyName, beanName);
        }
    }
}

上面的方法很簡單,就是尋找 bean 的非簡單類型並且不存在於 mbd.getPropertyValues() 中的屬性,然後遍歷調用 getBean() 方法去獲取實例,完成注入。

非簡單類型就是指除去8個原始類型、String類型、Number類型、Date類型、URL類型、URI類型的其它類型。

registerDependentBean() 方法在Spring IoC bean 的載入一文中有分析過,這裡不再贅述。

按照類型依賴注入

AbstractAutowireCapableBeanFactory#autowireByType

protected void autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
        converter = bw;
    }

    Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
    // 獲取bean中非簡單屬性
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
        try {
            PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
            // 根據類型注入永遠不要注入Object類型,你細細地品一下
            if (Object.class != pd.getPropertyType()) {
                // 獲取屬性的可寫方法,一般是set方法
                MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
                boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
                DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
                // 依賴解決,最後返回符合條件需要注入的bean實例
                Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
                if (autowiredArgument != null) {
                    // 需要注入的bean實例不為空,加入到pvc
                    pvs.add(propertyName, autowiredArgument);
                }
                for (String autowiredBeanName : autowiredBeanNames) {
                    // 註冊依賴關係
                    registerDependentBean(autowiredBeanName, beanName);
                }
                autowiredBeanNames.clear();
            }
        } catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
        }
    }
}

上面方法中的 resolveDependency() 方法在Spring IoC bean 的創建一文中介紹過,這裡不再贅述。

屬性賦值

AbstractAutowireCapableBeanFactory#applyPropertyValues

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
    // 屬性為空,直接返回
    if (pvs.isEmpty()) {
        return;
    }

    if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
        ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
    }

    MutablePropertyValues mpvs = null;
    List<PropertyValue> original;

    if (pvs instanceof MutablePropertyValues) {
        mpvs = (MutablePropertyValues) pvs;
        // 快捷方式,如果屬性已經轉換過,直接填充進BeanWrapper
        if (mpvs.isConverted()) {
            try {
                bw.setPropertyValues(mpvs);
                return;
            } catch (BeansException ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);
            }
        }
        // 屬性沒有轉換過,獲取屬性列表
        original = mpvs.getPropertyValueList();
    } else {
        // 獲取屬性列表
        original = Arrays.asList(pvs.getPropertyValues());
    }

    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
        converter = bw;
    }
    // 獲取對應的解析器
    BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

    // 創建深拷貝,解決引用的問題
    List<PropertyValue> deepCopy = new ArrayList<>(original.size());
    boolean resolveNecessary = false;
    // 遍歷屬性,將屬性轉換為對應的類型
    for (PropertyValue pv : original) {
        // 如果pv類型轉換過,直接添加進deepCopy
        if (pv.isConverted()) {
            deepCopy.add(pv);
        } else {
            // 進行轉換
            // 拿到pv原始屬性名和屬性值
            String propertyName = pv.getName();
            Object originalValue = pv.getValue();
            if (originalValue == AutowiredPropertyMarker.INSTANCE) {
                Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
                if (writeMethod == null) {
                    throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
                }
                originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
            }
            // 進行類型轉換
            Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
            Object convertedValue = resolvedValue;
            boolean convertible = bw.isWritableProperty(propertyName) &&
                !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
            if (convertible) {
                // 如果可轉換,則轉換指定目標屬性的給定值
                convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
            }
            // 在合併的BeanDefinition中存儲轉換後的值,以避免為每個創建的bean實例重新轉換
            if (resolvedValue == originalValue) {
                if (convertible) {
                    pv.setConvertedValue(convertedValue);
                }
                deepCopy.add(pv);
            } else if (convertible && originalValue instanceof TypedStringValue &&
                       !((TypedStringValue) originalValue).isDynamic() &&
                       !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                pv.setConvertedValue(convertedValue);
                deepCopy.add(pv);
            } else {
                resolveNecessary = true;
                deepCopy.add(new PropertyValue(pv, convertedValue));
            }
        }
    }
    if (mpvs != null && !resolveNecessary) {
        mpvs.setConverted();
    }

    try {
        // 填充bean屬性值
        bw.setPropertyValues(new MutablePropertyValues(deepCopy));
    } catch (BeansException ex) {
        throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Error setting property values", ex);
    }
}

上面程式碼中的 bw.setPropertyValues() 方法最終會調用 BeanWrapperImpl#setVlaue() 方法,如下:

public void setValue(final @Nullable Object value) throws Exception {
    // 這裡一般就是set方法
    final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
((GenericTypeAwarePropertyDescriptor)this.pd).getWriteMethodForActualAccess() : this.pd.getWriteMethod());
    // 利用反射調用set方法給屬性賦值
    ReflectionUtils.makeAccessible(writeMethod);
    writeMethod.invoke(getWrappedInstance(), value);

}

下圖是我 debug 時的截圖,可以看到基本上就是在調用屬性的 setter 方法:

注意:沒有 setter 方法時會拋出異常。

總結

本篇文章主要分析了 Spring IoC 的屬性賦值階段的流程,Spring 在此階段也提供了2個擴展點;分別是 bean 的實例化後和屬性賦值前,即 InstantiationAwareBeanPostProcessor 介面的 postProcessAfterInstantiation() 方法和 postProcessProperties() 方法。需要注意的是在 XML 中配置的 autowire 屬性,不管是 byName 還是 byType 都需要 setter 方法,但是我們平時在使用 @Autowire 註解時並不需要 settter 方法,原因會在分析 @Autowire 註解時講述。