SpringBoot源码解析 -- @Value,@Autowired实现原理

SpringBoot深入理解 -- @AliasFor注解的作用
SpringBoot源码解析 -- SpringBoot启动过程
SpringBoot源码解析 -- AutoConfigure的实现原理
SpringBoot源码解析 -- @ComponentScan的实现原理
SpringBoot源码解析 -- @Value,@Autowired实现原理
SpringBoot源码解析 -- Tomcat,SpringMVC启动
SpringBoot源码解析 -- Logging,Environment启动

前面解析@ComponentScan实现原理的文章说了,Spring如何扫描@Component注解的Bean,但扫描的Bean如何注入属性呢?
我们都知道该功能主要使用@Value,@Autowired注解完成,这篇文章主要解析Spring中@Value,@Autowired实现原理。
源码分析基于spring boot 2.1

前面解析Spring注入属性过程的文章中,说过AbstractAutowireCapableBeanFactory#populateBean方法负责注入bean的属性,其实@Value,@Autowired等注解也是在该方法处理。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    ...
    PropertyDescriptor[] filteredPds = null;
    if (hasInstAwareBpps) {
        if (pvs == null) {
            pvs = mbd.getPropertyValues();
        }
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                // #1
                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);
                    if (pvsToUse == null) {
                        return;
                    }
                }
                pvs = pvsToUse;
            }
        }
    }
    ...
}

#1 调用InstantiationAwareBeanPostProcessor#postProcessProperties扩展方法,这里处理@Value,@Autowired等注解。

在解析SpringBoot启动过程的文章中,说过了AutowiredAnnotationBeanPostProcessor负责处理@Value,@Autowired等注解。
(AutowiredAnnotationBeanPostProcessor是InstantiationAwareBeanPostProcessor的实现类)
AutowiredAnnotationBeanPostProcessor#postProcessProperties

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    // #1
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);    
    try {
        // #2
        metadata.inject(bean, beanName, pvs);   
    }
    ...
    return pvs;
}

#1 获取Class中关于属性注入相关注解的元数据
#2 完成属性注入操作

AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata -> buildAutowiringMetadata

    private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
        LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
        Class<?> targetClass = clazz;

        do {
            final LinkedList<InjectionMetadata.InjectedElement> currElements =
                    new LinkedList<InjectionMetadata.InjectedElement>();

            ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
                @Override
                public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
                    // #1
                    AnnotationAttributes ann = findAutowiredAnnotation(field);
                    if (ann != null) {
                        if (Modifier.isStatic(field.getModifiers())) {
                            if (logger.isWarnEnabled()) {
                                logger.warn("Autowired annotation is not supported on static fields: " + field);
                            }
                            return;
                        }
                        boolean required = determineRequiredStatus(ann);
                        currElements.add(new AutowiredFieldElement(field, required));
                    }
                }
            });

            ... // #2

            elements.addAll(0, currElements);
            targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);

        return new InjectionMetadata(clazz, elements);
    }

#1 查找field是否有@Autowired,@Value等注解
#2 查找method是否有@Autowired,@Value等注解

InjectionMetadata#inject方法遍历所有的InjectedElement,调用AutowiredMethodElement,AutowiredFieldElement的inject方法,这里只关注AutowiredFieldElement#inject
InjectionMetadata#inject -> AutowiredFieldElement#inject

protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
    Field field = (Field) this.member;
    Object value;
    if (this.cached) {
        value = resolvedCachedArgument(beanName, this.cachedFieldValue);
    }
    else {
        DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
        desc.setContainingClass(bean.getClass());
        Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
        TypeConverter typeConverter = beanFactory.getTypeConverter();
        try {
            // #1
            value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);   
        }
        catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
        }
        ...
    }
    if (value != null) {
        // #2
        ReflectionUtils.makeAccessible(field);  
        field.set(bean, value);
    }
}

#1 根据注解元数据,解析属性值
#2 将解析的结果值注入到bean

DefaultListableBeanFactory#resolveDependency -> DefaultListableBeanFactory#doResolveDependency

public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
        Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {

    InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
    try {
        Object shortcut = descriptor.resolveShortcut(this);
        if (shortcut != null) {
            return shortcut;
        }

        Class<?> type = descriptor.getDependencyType();
        // #1
        Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);    
        if (value != null) {
            if (value instanceof String) {
                // #2
                String strVal = resolveEmbeddedValue((String) value);   
                BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
                value = evaluateBeanDefinitionString(strVal, bd);
            }
            //#3
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); 
            return (descriptor.getField() != null ?
                    converter.convertIfNecessary(value, type, descriptor.getField()) :
                    converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
        }

        // #4
        Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);   
        if (multipleBeans != null) {
            return multipleBeans;
        }

        // #5
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); 
        if (matchingBeans.isEmpty()) {
            if (isRequired(descriptor)) {
                raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
            }
            return null;
        }

        String autowiredBeanName;
        Object instanceCandidate;

        // #6
        if (matchingBeans.size() > 1) {
            autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);  
            if (autowiredBeanName == null) {
                if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                    return descriptor.resolveNotUnique(type, matchingBeans);
                }
                else {
                    return null;
                }
            }
            instanceCandidate = matchingBeans.get(autowiredBeanName);
        }
        else {
            Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
            autowiredBeanName = entry.getKey();
            instanceCandidate = entry.getValue();
        }

        if (autowiredBeanNames != null) {
            autowiredBeanNames.add(autowiredBeanName);
        }
        return (instanceCandidate instanceof Class ?
                descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
    }
    finally {
        ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
    }
}

#1 如果存在@Value注解,获取注解的value值
#2 解析@Value注解的值,如果这里使用占位符引用了配置文件,默认使用PropertyPlaceholderConfigurer#PlaceholderResolvingStringValueResolver解析配置文件中的值。
PropertyPlaceholderConfigurer是一个常用的BeanFactoryPostProcessor,它可以在Spring启动时,将Bean属性配置的占位符解析为配置属性的值
#3 默认使用SimpleTypeConverter将配置值转化为属性要求的类型(例如属性为int类型,则需要将String转换为int类型)
这里最终也会复用TypeConverterDelegate#convertIfNecessary方法。
#4 解析数组、list、map等类型的依赖,使用对应的TypeConverter处理
#5 处理@Autowire,找到候选的bean
#6 存在多个候选的bean,spring要按优先级决定用哪个,较复杂,不深入。

DefaultListableBeanFactory#findAutowireCandidates

protected Map<String, Object> findAutowireCandidates(
        String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {

    // #1
    String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this, requiredType, true, descriptor.isEager());    
    Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);
    // #2
    for (Class<?> autowiringType : this.resolvableDependencies.keySet()) {  
        if (autowiringType.isAssignableFrom(requiredType)) {
            Object autowiringValue = this.resolvableDependencies.get(autowiringType);
            autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
            if (requiredType.isInstance(autowiringValue)) {
                result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
                break;
            }
        }
    }
    //#3
    for (String candidate : candidateNames) {
        if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {  
            addCandidateEntry(result, candidate, descriptor, requiredType);
        }
    }
    ...
    return result;
}

#1 按类型查找spring上下文中所有的bean
#2 从当前已存在的依赖关系中查找
#3 遍历#1步骤中找到的bean,如果满足Autowire要求,添加到结果
这里检查候选类的类型是否匹配,是否满足@Qualifier的要求,不继续深入,有兴趣的同学自行阅读源码。

如果您觉得本文不错,欢迎关注我的微信公众号,您的关注是我坚持的动力!


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 223,207评论 6 521
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 95,455评论 3 400
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 170,031评论 0 366
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 60,334评论 1 300
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 69,322评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,895评论 1 314
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,300评论 3 424
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,264评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,784评论 1 321
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,870评论 3 343
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,989评论 1 354
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,649评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,331评论 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,814评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,940评论 1 275
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,452评论 3 379
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,995评论 2 361