Spring依賴注入解析過(guò)程

上文討論了Spring在進(jìn)行依賴注入的時(shí)候嫩舟,如何查找一個(gè)bean的依賴屬性氢烘,本文則討論在進(jìn)行依賴屬性的查找之前,進(jìn)行依賴查找之前的處理流程

在Spring容器中家厌,有兩個(gè)重要的內(nèi)置bean后置處理器威始,它們是AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor

AutowiredAnnotationBeanPostProcessor完成了對(duì)標(biāo)注@Autowired@Value像街、@Inject屬性的注入

CommonAnnotationBeanPostProcessor完成了對(duì)JSR-250相關(guān)注解屬性的注入黎棠,如@WebServiceRef@EJB镰绎、@Resource脓斩,同時(shí),它也完成了一部分bean生命周期方法的處理畴栖,即@PostConstruct随静、@PreDestroy方法的回調(diào)

二者的功能類似,下面以AutowiredAnnotationBeanPostProcessor進(jìn)行講解

AutowiredAnnotationBeanPostProcessor實(shí)現(xiàn)了MergedBeanDefinitionPostProcessor接口的postProcessMergedBeanDefinition方法

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
        implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {

    // 緩存bean的注入屬性元數(shù)據(jù)
    private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);

    // ...

    /**
     * 解析當(dāng)前bean需要注入的屬性信息吗讶,生成一個(gè)注入屬性元數(shù)據(jù)InjectionMetadata 
     */
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        metadata.checkConfigMembers(beanDefinition);
    }

    private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
        // Fall back to class name as cache key, for backwards compatibility with custom callers.
        String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
        // Quick check on the concurrent map first, with minimal locking.
        InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
            synchronized (this.injectionMetadataCache) {
                metadata = this.injectionMetadataCache.get(cacheKey);
                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                    if (metadata != null) {
                        metadata.clear(pvs);
                    }
                    // 解析當(dāng)前類要注入的屬性的元數(shù)據(jù)
                    metadata = buildAutowiringMetadata(clazz);
                    // 緩存當(dāng)前類要注入屬性的元數(shù)據(jù)信息
                    this.injectionMetadataCache.put(cacheKey, metadata);
                }
            }
        }
        return metadata;
    }
 
    private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {

        // ...
        List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
        Class<?> targetClass = clazz;

        do {  // 循環(huán)操作
            final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

            // 解析標(biāo)注了注解的屬性
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
                // 判斷是否標(biāo)注了相關(guān)注解信息
                MergedAnnotation<?> ann = findAutowiredAnnotation(field);
                if (ann != null) {
                    if (Modifier.isStatic(field.getModifiers())) {
                        return;  // 可見燎猛,static屬性是不會(huì)注入的
                    }
                    boolean required = determineRequiredStatus(ann);
                    currElements.add(new AutowiredFieldElement(field, required));
                }
            });
            // 解析標(biāo)注了注解的方法
            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                    return;
                }
                MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
                if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                    if (Modifier.isStatic(method.getModifiers())) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Autowired annotation is not supported on static methods: " + method);
                        }
                        return;
                    }
                    if (method.getParameterCount() == 0) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Autowired annotation should only be used on methods with parameters: " +
                                    method);
                        }
                    }
                    boolean required = determineRequiredStatus(ann);
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    currElements.add(new AutowiredMethodElement(method, required, pd));
                }
            });
            // 加到列表的頭部,注意照皆,由于每次都放置在隊(duì)列頭部
            // 而解析從子類遞進(jìn)到父類重绷,則父類的數(shù)據(jù)會(huì)在前部
            elements.addAll(0, currElements);
            // 獲取父類信息,準(zhǔn)備開始下一次循環(huán)
            targetClass = targetClass.getSuperclass();
        } while (targetClass != null && targetClass != Object.class);

        return InjectionMetadata.forElements(elements, clazz);
    }

    // 判斷是否標(biāo)注了相關(guān)注解
    @Nullable
    private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
        MergedAnnotations annotations = MergedAnnotations.from(ao);
        for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
            MergedAnnotation<?> annotation = annotations.get(type);
            if (annotation.isPresent()) {
                return annotation;
            }
        }
        return null;
    }
}

到此一個(gè)bean的依賴屬性元數(shù)據(jù)被解析完畢膜毁,并緩存了起來(lái)昭卓,以上的步驟發(fā)生在實(shí)例化bean之后,屬性填充之前瘟滨,接著便是對(duì)這個(gè)實(shí)例化完畢的bean進(jìn)行屬性填充

AutowiredAnnotationBeanPostProcessor同樣實(shí)現(xiàn)了InstantiationAwareBeanPostProcessor接口的postProcessProperties方法候醒,該方法用來(lái)對(duì)屬性進(jìn)行填充

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
        implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {

    // 緩存bean的注入屬性元數(shù)據(jù)
    private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        // 獲取前面解析完畢的依賴屬性元數(shù)據(jù)
        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;
    }
}
public class InjectionMetadata {
  
    // ...

    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) {
                // 通過(guò)循環(huán),依次將屬性注入目標(biāo)bean
                element.inject(target, beanName, pvs);
            }
        }
    }
}

AutowiredAnnotationBeanPostProcessor存在兩個(gè)內(nèi)部類AutowiredFieldElement杂瘸、AutowiredMethodElement倒淫,此處使用字段注入舉例

private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
    // ...
    
    @Override
    protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
        // ...

        DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
        desc.setContainingClass(bean.getClass());
        Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
        Assert.state(beanFactory != null, "No BeanFactory available");
        TypeConverter typeConverter = beanFactory.getTypeConverter();
        try {
            // 這里就是上文依賴查找的調(diào)用發(fā)起的地方
            value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
        } catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
        }
        // ...
        if (value != null) {
            // 最后如果獲取到的屬性bean不為null,將其注入到目標(biāo)bean中
            ReflectionUtils.makeAccessible(field);
            field.set(bean, value);
        }
    }
}

參考圖:

依賴注入屬性的解析過(guò)程.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末败玉,一起剝皮案震驚了整個(gè)濱河市敌土,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绒怨,老刑警劉巖纯赎,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異南蹂,居然都是意外死亡犬金,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門六剥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)晚顷,“玉大人,你說(shuō)我怎么就攤上這事疗疟「媚” “怎么了?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵策彤,是天一觀的道長(zhǎng)栓袖。 經(jīng)常有香客問(wèn)我匣摘,道長(zhǎng),這世上最難降的妖魔是什么裹刮? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任音榜,我火速辦了婚禮,結(jié)果婚禮上捧弃,老公的妹妹穿的比我還像新娘赠叼。我一直安慰自己,他們只是感情好违霞,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布嘴办。 她就那樣靜靜地躺著,像睡著了一般买鸽。 火紅的嫁衣襯著肌膚如雪涧郊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天癞谒,我揣著相機(jī)與錄音底燎,去河邊找鬼。 笑死弹砚,一個(gè)胖子當(dāng)著我的面吹牛双仍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播桌吃,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼朱沃,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了茅诱?” 一聲冷哼從身側(cè)響起逗物,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瑟俭,沒想到半個(gè)月后翎卓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摆寄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年失暴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片微饥。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡逗扒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出欠橘,到底是詐尸還是另有隱情矩肩,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布肃续,位于F島的核電站黍檩,受9級(jí)特大地震影響叉袍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜刽酱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一畦韭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧肛跌,春花似錦、人聲如沸察郁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)皮钠。三九已至稳捆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間麦轰,已是汗流浹背乔夯。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留款侵,地道東北人末荐。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像新锈,于是被迫代替她去往敵國(guó)和親甲脏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359