spring源碼解析 -- 注入屬性

Spring源碼解析 -- 讀取bean元數(shù)據(jù)
spring源碼解析 -- 構(gòu)造bean
spring源碼解析 -- 注入屬性
spring源碼解析 -- Spring Context
Spring源碼解析 -- AOP原理(1)
Spring源碼解析 -- AOP原理(2)
Spring源碼解析 -- SpringMvc原理

前面的文件已經(jīng)解析了Spring構(gòu)造bean(未注入屬性)的過程尽棕,現(xiàn)在繼續(xù)解析spring注入屬性的過程唠叛。
關(guān)于閱讀源碼的思路布讹,可參考 -- 如何閱讀java源碼

在解析spring讀取xml配置的文章說過咖驮,spring會將xml屬性配置信息轉(zhuǎn)化為spring內(nèi)部的表示類纵朋,并結(jié)合屬性name捞奕,type等元數(shù)據(jù)構(gòu)造PropertyValue容燕,存放在BeanDefinition#propertyValues。
而在解析spring構(gòu)造bean的文章中說過缨伊,spring注入屬性的方法在
AbstractAutowireCapableBeanFactory#populateBean

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
    protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
        PropertyValues pvs = mbd.getPropertyValues();

        ...
        boolean continueWithPropertyPopulation = true;

        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {  // #1
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {    // #2
                        continueWithPropertyPopulation = false;
                        break;
                    }
                }
            }
        }

        if (!continueWithPropertyPopulation) {
            return;
        }

        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

            // Add property values based on autowire by name if applicable.
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { // #3
                autowireByName(beanName, mbd, bw, newPvs);
            }

            // Add property values based on autowire by type if applicable.
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { // #4
                autowireByType(beanName, mbd, bw, newPvs);
            }

            pvs = newPvs;
        }

        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

        if (hasInstAwareBpps || needsDepCheck) {    // #5
            PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            if (hasInstAwareBpps) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                        pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvs == null) {
                            return;
                        }
                    }
                }
            }
            if (needsDepCheck) {
                checkDependencies(beanName, mbd, filteredPds, pvs);
            }
        }

        applyPropertyValues(beanName, mbd, bw, pvs);    // #6
    }

}

#1 查找spring上下文是否存在InstantiationAwareBeanPostProcessor摘刑。
InstantiationAwareBeanPostProcessor也是spring提供的擴展接口,它繼承自BeanPostProcessor刻坊,并添加了postProcessBeforeInstantiation枷恕,postProcessAfterInstantiation,postProcessPropertyValues這三個方法谭胚。
#2 存在InstantiationAwareBeanPostProcessor徐块,調(diào)用postProcessAfterInstantiation方法
#3 處理通過name自動裝配
#4 處理通過type自動裝配
#5 調(diào)用InstantiationAwareBeanPostProcessor#postProcessPropertyValues擴展方法,很重要灾而,這里完成@Value胡控,@Autowired注解的解析,后面有對應(yīng)文章解析
#6 解析BeanDefinition#propertyValues中的屬性

AbstractAutowireCapableBeanFactory#autowireByName

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

    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
        if (containsBean(propertyName)) {
            Object bean = getBean(propertyName);    // #1
            pvs.add(propertyName, bean);    // #2
            registerDependentBean(propertyName, beanName);  // #3
            if (logger.isDebugEnabled()) {
                logger.debug("Added autowiring by name from bean name '" + beanName +
                        "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
            }
        }
        else {
            ...
        }
    }
}

#1 通過name獲取bean
#2 添加到BeanDefinition#propertyValues旁趟,交給下面流程處理
#3 聲明bean之間的依賴铜犬,bean銷毀時要判斷bean的依賴
autowireByType這里就不復(fù)述了。

AbstractAutowireCapableBeanFactory#applyPropertyValues

    protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
        ...

        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.
        List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
        boolean resolveNecessary = false;
        for (PropertyValue pv : original) {
            if (pv.isConverted()) {
                deepCopy.add(pv);   // #1
            }
            else {
                String propertyName = pv.getName();
                Object originalValue = pv.getValue();
                Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);    // #2
                Object convertedValue = resolvedValue;
                boolean convertible = bw.isWritableProperty(propertyName) &&
                        !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
                if (convertible) {
                    convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);    // #3
                }
                // Possibly store converted value in merged bean definition,
                // in order to avoid re-conversion for every created bean instance.
                if (resolvedValue == originalValue) {
                    if (convertible) {
                        pv.setConvertedValue(convertedValue);   // #4
                    }
                    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;    // #5
                    deepCopy.add(new PropertyValue(pv, convertedValue));
                }
            }
        }
        if (mpvs != null && !resolveNecessary) {
            mpvs.setConverted();
        }

        // Set our (possibly massaged) deep copy.
        try {
            bw.setPropertyValues(new MutablePropertyValues(deepCopy));  // #6
        }
        catch (BeansException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Error setting property values", ex);
        }
    }

#1 屬性已處理轻庆,直接復(fù)用
#2 解析bean引用(如RuntimeBeanReference癣猾,RuntimeBeanNameReference),獲取引用的bean余爆,對于集合屬性纷宇,如ManagedArray,ManagedList蛾方,如果集合中的元素是bean引用像捶,也會被解析
TypedStringValue則會提取value的值。
#3 根據(jù)目標屬性進行轉(zhuǎn)換
xml配置都是string桩砰,如果屬性的類型是long拓春,date,這里進行轉(zhuǎn)換
#4 緩存結(jié)果亚隅,避免每次構(gòu)建bean時都重復(fù)操作
#5 無法緩存硼莽,只能復(fù)制結(jié)果用于后面流程
#6 賦值給bean

轉(zhuǎn)化

下面看看轉(zhuǎn)化過程
AbstractAutowireCapableBeanFactory#convertForProperty

    private Object convertForProperty(Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {
        if (converter instanceof BeanWrapperImpl) {         
            return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);   // #1
        }
        else {
            PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
            MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
            return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);  // #2
        }
    }

#1 默認的轉(zhuǎn)化方式
#2 使用自定義轉(zhuǎn)化方式

看看默認的轉(zhuǎn)化方式,BeanWrapperImpl#convertForProperty -> TypeConverterDelegate#convertIfNecessary

    public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
            Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {

        PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);

        ConversionFailedException conversionAttemptEx = null;

        ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
        if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {    // #1
            TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
            if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
                try {
                    return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
                }
                catch (ConversionFailedException ex) {
                    // fallback to default conversion logic below
                    conversionAttemptEx = ex;
                }
            }
        }

        Object convertedValue = newValue;

        if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {  // #2
            if (typeDescriptor != null && requiredType != null && Collection.class.isAssignableFrom(requiredType) &&
                    convertedValue instanceof String) {
                TypeDescriptor elementTypeDesc = typeDescriptor.getElementTypeDescriptor();
                if (elementTypeDesc != null) {
                    Class<?> elementType = elementTypeDesc.getType();
                    if (Class.class == elementType || Enum.class.isAssignableFrom(elementType)) {
                        convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
                    }
                }
            }
            if (editor == null) {
                editor = findDefaultEditor(requiredType);
            }
            convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
        }

        boolean standardConversion = false;

        if (requiredType != null) {
            // Try to apply some standard type conversion rules if appropriate.

            if (convertedValue != null) {
                if (Object.class == requiredType) {
                    return (T) convertedValue;
                }
                else if (requiredType.isArray()) {  // #3
                    if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
                        convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
                    }
                    return (T) convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
                }
                ...
            }
            else {
                // convertedValue == null
                if (javaUtilOptionalEmpty != null && requiredType == javaUtilOptionalEmpty.getClass()) {
                    convertedValue = javaUtilOptionalEmpty; // #4
                }
            }

            if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
                ... // #5
            }
        }

        

        return (T) convertedValue;
    }

#1 PropertyEditor為空煮纵,使用ConversionService
#2 PropertyEditor不為空懂鸵,使用PropertyEditor
#3 處理數(shù)組,集合等類型的屬性行疏,這里會遍歷集合元素匆光,遞歸調(diào)用convertIfNecessary轉(zhuǎn)化,再收集處理結(jié)果酿联。
#4 對轉(zhuǎn)化結(jié)果是空值的情況進行處理
#5 異常情況终息,會重復(fù)調(diào)用一遍conversionService
PropertyEditor夺巩,ConversionService都可以自定義屬性的轉(zhuǎn)化操作。

賦值

AbstractAutowireCapableBeanFactory#applyPropertyValues方法#6步驟負責賦值給bean的屬性周崭。
這里調(diào)用AbstractNestablePropertyAccessor#setPropertyValues -> AbstractNestablePropertyAccessor#setPropertyValue

    public void setPropertyValue(PropertyValue pv) throws BeansException {
        PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens;
        if (tokens == null) {
            String propertyName = pv.getName();
            AbstractNestablePropertyAccessor nestedPa;
            try {
                nestedPa = getPropertyAccessorForPropertyPath(propertyName);    // #1
            }
            catch (NotReadablePropertyException ex) {
                throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
                        "Nested property in path '" + propertyName + "' does not exist", ex);
            }
            tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
            if (nestedPa == this) {
                pv.getOriginalPropertyValue().resolvedTokens = tokens;
            }
            nestedPa.setPropertyValue(tokens, pv);  // #2
        }
        else {
            setPropertyValue(tokens, pv);
        }
    }

#1 根據(jù)propertyName獲取不同的屬性訪問器(set方法引用)
getPropertyAccessorForPropertyPath返回的是BeanWrapperImpl劲够,他繼承了AbstractNestablePropertyAccessor。
這里支持嵌套屬性休傍,如Blog中存在author屬性,而Author存在name屬性蹲姐,對Blog的bean可配置author.name磨取,這里返回的是blog的author屬性對應(yīng)的BeanWrapperImpl。

#2
AbstractNestablePropertyAccessor#setPropertyValue -> AbstractNestablePropertyAccessor#processLocalProperty -> PropertyHandler#setValue -> BeanWrapperImpl#setValue
可以看到直接調(diào)用set方法了柴墩。

如果您覺得本文不錯忙厌,歡迎關(guān)注我的微信公眾號,您的關(guān)注是我堅持的動力江咳!


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末逢净,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子歼指,更是在濱河造成了極大的恐慌爹土,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件踩身,死亡現(xiàn)場離奇詭異胀茵,居然都是意外死亡,警方通過查閱死者的電腦和手機挟阻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門琼娘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人附鸽,你說我怎么就攤上這事脱拼。” “怎么了坷备?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵熄浓,是天一觀的道長。 經(jīng)常有香客問我省撑,道長玉组,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任丁侄,我火速辦了婚禮惯雳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鸿摇。我一直安慰自己石景,他們只是感情好,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著潮孽,像睡著了一般揪荣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上往史,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天仗颈,我揣著相機與錄音,去河邊找鬼椎例。 笑死挨决,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的订歪。 我是一名探鬼主播脖祈,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼刷晋!你這毒婦竟也來了盖高?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤眼虱,失蹤者是張志新(化名)和其女友劉穎喻奥,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捏悬,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡映凳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了邮破。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诈豌。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖抒和,靈堂內(nèi)的尸體忽然破棺而出矫渔,到底是詐尸還是另有隱情颊亮,我是刑警寧澤销凑,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布委可,位于F島的核電站亡问,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏老厌。R本人自食惡果不足惜边翼,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一腮敌、第九天 我趴在偏房一處隱蔽的房頂上張望征懈。 院中可真熱鬧石咬,春花似錦、人聲如沸卖哎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至焕窝,卻和暖如春蹬挺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背它掂。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工巴帮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人虐秋。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓榕茧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親熟妓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容