Spring IoC 屬性賦值階段

前言

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

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

正文

咱們在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() 若是返回空會直接跳過屬性填充階段,不爲空直接使用返回的 PropertyValuesapp

按照名稱依賴注入

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類型的其它類型。post

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

按照類型依賴注入

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 的建立一文中介紹過,這裏再也不贅述。spa

屬性賦值

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() 方法,以下:debug

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 方法:code

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

總結

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

相關文章
相關標籤/搜索