我是靠谱客的博主 狂野小白菜,最近开发中收集的这篇文章主要介绍Spring源码分析(十)依赖注入源码解析3:DefaultListableBeanFactory#doResolveDependency 真正开始解析依赖项4.2 真正开始解析依赖项(最核心方法)a. 依赖注入的缓存b. 获取@Value所指定的值c. 占位符填充(${})d. 解析Spring表达式(#{})e. 将value转换为descriptor所对应的类型f. 注入多实例情况g. 根据类型查找所有候选Beanh. 如果根据类型匹配到了多个Beani. 记录匹配过的BeanNamej.,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

4.2 真正开始解析依赖项(最核心方法)

org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency

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

    //线程上设置当前注入点
    InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
    try {
        //a.依赖注入的缓存,有缓存直接返回
        //	如果descriptor是ShortcutDependencyDescriptor,相当于之前做过依赖注入且已经缓存了
        //	那么直接根据缓存的BeanName,去容器里直接拿Bean
        Object shortcut = descriptor.resolveShortcut(this);
        if (shortcut != null) {
            return shortcut;
        }
    	//获取依赖注入的参数类型
        Class<?> type = descriptor.getDependencyType();
        //b.获取@Value所指定的值
        Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
        if (value != null) {
            //如果拿到是String:
            if (value instanceof String) {
                //c.解析嵌入值,占位符填充(${})
                String strVal = resolveEmbeddedValue((String) value);
                BeanDefinition bd = (beanName != null && containsBean(beanName) ?
                        getMergedBeanDefinition(beanName) : null);
                //d.解析Spring表达式(#{})
                //(根据Spring表达式得到的对象有可能直接就是一个Bean对象,也有可能是其他)
                value = evaluateBeanDefinitionString(strVal, bd);
            }
            //e.将value转换为descriptor所对应的类型
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            try {
                return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
            }
            catch (UnsupportedOperationException ex) {...}
        }
    	//f.注入多实例情况
        //如果descriptor对应的类型是数组、Map、集合这些,就拿descriptor对应的类型去匹配所有的bean对象,不用进一步做筛选了
        Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
        if (multipleBeans != null) {
            return multipleBeans;
        }

        //g.根据类型查找所有候选Bean
        //	找到所有Bean,key是BeanName,value有可能是Bean对象,有可能是BeanClass
        //		依赖注入过程中,没必要把所有候选Bean都实例化
        //		因为后续流程最多只会注入一个,保证注入的那个实例化过就OK了
        //		而且后续判断是否匹配,有Class就够了
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
        if (matchingBeans.isEmpty()) {
            //required为true,且matchingBeans为空,则抛异常
            if (isRequired(descriptor)) {
                raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
            }
            //如果required不为true,则注入一个空属性
            return null;
        }

        String autowiredBeanName;
        Object instanceCandidate;

        if (matchingBeans.size() > 1) {
            //h.如果根据类型匹配到了多个Bean
            //根据类型找到了多个Bean,进一步筛选出某一个 @Primary --> 优先级最高 --> name
            autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
            if (autowiredBeanName == null) {
                //如果筛选不出来
                if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                    //如果required为true 或 type不是数组、集合、map
                    //indicatesMultipleBeans:判断type是否是 数组、集合、map
                    //这里直接抛异常
                    return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
                }
                else {
                    // In case of an optional Collection/Map, silently ignore a non-unique case:
                    // possibly it was meant to be an empty collection of multiple regular beans
                    // (before 4.3 in particular when we didn't even look for collection beans).
                    // 在可选的Collection/Map的情况下,无声地忽略一个非唯一的情况:
                    // 它可能是多个常规bean的空集合(特别是在4.3之前,当我们甚至没有查找集合bean时)。
                    return null;
                }
            }
            //筛选出一个
            instanceCandidate = matchingBeans.get(autowiredBeanName);
        }
        else {
            // We have exactly one match.
            // 根据类型只匹配到一个
            Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
            autowiredBeanName = entry.getKey();
            instanceCandidate = entry.getValue();
        }

        //i.记录匹配过的BeanName
        if (autowiredBeanNames != null) {
            autowiredBeanNames.add(autowiredBeanName);
        }
        //j.有可能筛选出来的是某个bean的类型,此处就进行实例化,调用getBean
        if (instanceCandidate instanceof Class) {
            instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
        }
        Object result = instanceCandidate;
        //k:NullBean
        if (result instanceof NullBean) {
            if (isRequired(descriptor)) {
                //解析出来是NullBean,且required=true,则抛异常
                raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
            }
            result = null;
        }
        //判断找到的Bean对象类型是否是期望注入的类型
        if (!ClassUtils.isAssignableValue(type, result)) {
            throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
        }
        //最终返回
        return result;
    }
    finally {
        ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
    }
}

a. 依赖注入的缓存

缓存是什么时候放的呢?

以字段注入为例,回到上一节入口分析字段注入的时候:

private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
    //构造依赖描述符对象
    DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
    desc.setContainingClass(bean.getClass());
    //autowiredBeanNames记录了需要注入的Bean的BeanName
    Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
    Assert.state(beanFactory != null, "No BeanFactory available");
    //类型转换器
    TypeConverter typeConverter = beanFactory.getTypeConverter();
    Object value;
    try {
        //核心方法,从工厂中解析依赖项要注入的值
        value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
    }
    catch (BeansException ex) {...}
    synchronized (this) {
        //拿到结果以后,判断是否缓存过了,没有就进行缓存
        if (!this.cached) {
            Object cachedFieldValue = null;
            if (value != null || this.required) {
                cachedFieldValue = desc;
                //注册一下beanName依赖了autowiredBeanNames
                registerDependentBeans(beanName, autowiredBeanNames);
                //只有当前注入只会注入一个Bean的情况下才会缓存
                //	比如如果字段类型是List<Xxx>,那autowiredBeanNames有可能是多个
                if (autowiredBeanNames.size() == 1) {
                    String autowiredBeanName = autowiredBeanNames.iterator().next();
                    //工厂中包含这个Bean实例,且类型匹配是OK的,则进行缓存
                    if (beanFactory.containsBean(autowiredBeanName) &&
                            beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                        //构造一个ShortcutDependencyDescriptor作为缓存,保存了当前field所匹配的autowiredBeanName
                        cachedFieldValue = new ShortcutDependencyDescriptor(
                                desc, autowiredBeanName, field.getType());
                    }
                }
            }
            //标记/保存缓存
            this.cachedFieldValue = cachedFieldValue;
            this.cached = true;
        }
    }
    return value;
}

看到缓存的对象类型就是ShortcutDependencyDescriptor,并且缓存的是BeanName!不是实例。
beanName是存在名为shortcut的成员变量:
在这里插入图片描述

缓存是什么时候用的呢?

比如原型Bean的情况,当第二次获取原型Bean,第二次注入的时候,会再次调用注入方法,还是以字段注入为例:
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    Field field = (Field) this.member;
    Object value;
    if (this.cached) {
        //对于原型Bean,第一次创建的时候,也找注入点,然后进行注入,此时cached为false,注入完了之后cached为true
        //第二次创建的时候,先找注入点(此时会拿到缓存好的注入点),也就是AutowiredFieldElement对象,此时cache为ture
        //则会使用缓存cachedFieldValue,是一个ShortcutDependencyDescriptor对象
        //注入点并没有缓存被注入的具体Bean对象,而是BeanName,这样就能保证注入到不同的原型Bean对象
        try {
            value = resolvedCachedArgument(beanName, this.cachedFieldValue);
        }
        catch (NoSuchBeanDefinitionException ex) {...}
    }
    else {...}
    if (value != null) {
        //反射给field赋值
        ReflectionUtils.makeAccessible(field);
        field.set(bean, value);
    }
}

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#resolvedCachedArgument

private Object resolvedCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) {
    //cachedArgument此时就是ShortcutDependencyDescriptor,它是DependencyDescriptor子类
    if (cachedArgument instanceof DependencyDescriptor) {
        DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument;
        Assert.state(this.beanFactory != null, "No BeanFactory available");
        //将缓存好的DependencyDescriptor对象作为入参,继续调用resolveDependency
        return this.beanFactory.resolveDependency(descriptor, beanName, null, null);
    }
    else {
        return cachedArgument;
    }
}

继续调用beanFactory.resolveDependency,还是回到4.2 doResolveDependency方法:
在这里插入图片描述

默认实现DependencyDescriptor是返回null,但如果是缓存ShortcutDependencyDescriptor的实现:
在这里插入图片描述
shortcut存的就是BeanName,根据BeanName去容器里获取实例对象
为什么要这么做?这样就能保证注入到不同的原型Bean对象

b. 获取@Value所指定的值

@Value可以放在字段或方法入参上
在这里插入图片描述
@Value注释:

  • 在字段或方法/构造函数参数级别使用的注解,指示被注解元素的默认值表达式。
  • 通常用于表达式驱动或属性驱动的依赖注入。也支持处理程序方法参数的动态解析——例如,在Spring MVC中。
  • 一个常见的用例是使用#{systemProperties.myProp}风格的SpEL (Spring Expression Language)表达式注入值。或者,可以使用${my.app.myProp}风格的属性占位符注入值。

默认实现走
org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#getSuggestedValue

public Object getSuggestedValue(DependencyDescriptor descriptor) {
    //获取@Value注解上的value属性
    //1.从参数级别获取(针对被包装的字段或方法/构造函数参数关联的注解)
    Object value = findValue(descriptor.getAnnotations());
    if (value == null) {
        //2.方法级别上获取
        //获取方法/构造函数上@Value注解的value属性(方法/构造函数级别,而不是参数级别)
        MethodParameter methodParam = descriptor.getMethodParameter();
        if (methodParam != null) {
            //methodParam.getMethodAnnotations():
            //	该方法公开在方法/构造函数本身上声明的注解(即在方法/构造函数级别,而不是在参数级别)
            value = findValue(methodParam.getMethodAnnotations());
        }
    }
    return value;
}

参数或方法上获取到注解以后都会调findValue方法,获取@Value注解的value属性:
org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#findValue

protected Object findValue(Annotation[] annotationsToSearch) {
    if (annotationsToSearch.length > 0) {   // qualifier annotations have to be local
        //AnnotatedElementUtils是一个注解工具类
        //获取合并后的注解属性(包括父注解)
        //this.valueAnnotationType就是Value.class
        AnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes(
                AnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType);
        if (attr != null) {
            return extractValue(attr);
        }
    }
    return null;
}

protected Object extractValue(AnnotationAttributes attr) {
    //AnnotationUtils.VALUE = "value"
    Object value = attr.get(AnnotationUtils.VALUE);
    if (value == null) {
        throw new IllegalStateException("Value annotation must have a value attribute");
    }
    return value;
}

在这里插入图片描述

org.springframework.core.annotation.AnnotatedElementUtils#getMergedAnnotationAttributes(java.lang.reflect.AnnotatedElement, java.lang.Class<? extends java.lang.annotation.Annotation>)涉及到一个注解派生的概念,可以参考:
spring core:@Component的派生性

c. 占位符填充(${})

如果@Value拿到的是String,则会先解析嵌入值,进行占位符填充

底层就是拿testValue这个key,从Environment对象里找value(默认),找到就会替换,找不到就保持原样
在这里插入图片描述

而Environment包含了操作系统层的属性值、jvm层的属性值、properties文件(需要注册)中的属性值
jvm层的属性值-Dxxxx 的优先级比 properties文件配置的属性值 优先级高
在这里插入图片描述
在这里插入图片描述

org.springframework.beans.factory.support.AbstractBeanFactory#resolveEmbeddedValue

public String resolveEmbeddedValue(@Nullable String value) {
    if (value == null) {
        return null;
    }
    String result = value;
    for (StringValueResolver resolver : this.embeddedValueResolvers) {
    	//解析器解析
        result = resolver.resolveStringValue(result);
        if (result == null) {
            return null;
        }
    }
    return result;
}

解析细节就不深究了,看下StringValueResolver初始化入口,应该是这个(和工厂生命周期有关,以后讲):
org.springframework.context.support.PropertySourcesPlaceholderConfigurer#postProcessBeanFactory,是一个BeanFactoryPostProcessor。
在这里插入图片描述
在这里插入图片描述

通过根据配置器的PropertySources集合解析每个占位符,替换bean定义中的${…}占位符来进行处理,其中包括:

  • 所有环境属性源(如果存在一个环境)
  • 合并的本地属性(如果已指定)
  • 通过调用setPropertySources设置的任何属性源

如果调用setPropertySources,将忽略环境和本地属性。此方法旨在为用户提供对属性源的细粒度控制,一旦设置,配置器就不会对添加其他源进行任何假设。

d. 解析Spring表达式(#{})

在这里插入图片描述

Spring表达式(Spring EL)

org.springframework.beans.factory.support.AbstractBeanFactory#evaluateBeanDefinitionString

protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) {
    if (this.beanExpressionResolver == null) {
        return value;
    }

    Scope scope = null;
    if (beanDefinition != null) {
        String scopeName = beanDefinition.getScope();
        if (scopeName != null) {
            scope = getRegisteredScope(scopeName);
        }
    }
    //SpringEl表达式原理也很复杂...
    //解析Spring表达式(#{}),根据Spring表达式得到的对象有可能直接就是一个Bean对象,也有可能是其他
    return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
}

e. 将value转换为descriptor所对应的类型

比如:
在这里插入图片描述

@Value配置的就是一个普通字符串,但是注入需要的类型是OrderService

这时就会尝试用类型转换器进行转换(类型转换器用法第一节说过)
在这里插入图片描述

f. 注入多实例情况

如果descriptor对应的类型是数组、Map、集合…这些,就拿descriptor对应的类型去匹配所有的bean对象,不用进一步做筛选了

比如:
在这里插入图片描述

org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveMultipleBeans

private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
        @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {

    Class<?> type = descriptor.getDependencyType();

    //用于访问多个元素的流的依赖描述符标记。
    if (descriptor instanceof StreamDependencyDescriptor) {...}
    //数组情况
    else if (type.isArray()) {...}
    //集合情况
    else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
        //获取集合的泛型类型
        Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
        if (elementType == null) {
            return null;
        }
        //g. 核心方法,根据类型查找所有候选Bean
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
                new MultiElementDescriptor(descriptor));
        if (matchingBeans.isEmpty()) {
            return null;
        }
        //i. 记录匹配过的BeanName
        if (autowiredBeanNames != null) {
            autowiredBeanNames.addAll(matchingBeans.keySet());
        }
        TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
        //类型转换
        Object result = converter.convertIfNecessary(matchingBeans.values(), type);
        if (result instanceof List) {
            //如果是list做一下排序
            if (((List<?>) result).size() > 1) {
                //可以指定比较器,默认是OrderComparator
                Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
                if (comparator != null) {
                    ((List<?>) result).sort(comparator);
                }
            }
        }
        return result;
    }
    //Map情况
    else if (Map.class == type) {
        ResolvableType mapType = descriptor.getResolvableType().asMap();
        Class<?> keyType = mapType.resolveGeneric(0);
        //如果Map的key不是String,则不支持
        if (String.class != keyType) {
            return null;
        }
        //Map value的类型
        Class<?> valueType = mapType.resolveGeneric(1);
        if (valueType == null) {
            return null;
        }
        //g.核心方法,根据类型查找所有候选Bean
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
                new MultiElementDescriptor(descriptor));
        if (matchingBeans.isEmpty()) {
            return null;
        }
        //i. 记录匹配过的BeanName
        if (autowiredBeanNames != null) {
            autowiredBeanNames.addAll(matchingBeans.keySet());
        }
        return matchingBeans;
    }
    else {
        return null;
    }
}

其实无论哪种情况,都会调用findAutowireCandidates方法,根据类型查找所有候选Bean,这是一个核心方法。

g. 根据类型查找所有候选Bean

org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates
核心方法,见下一节。

h. 如果根据类型匹配到了多个Bean

org.springframework.beans.factory.support.DefaultListableBeanFactory#determineAutowireCandidate

protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
    Class<?> requiredType = descriptor.getDependencyType();
    //candidates表示根据类型所找到的多个Bean,value有可能是class,有可能是Bean实例
    
    //i. 判断这些Bean中是否有一个是@Primary的
    String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
    if (primaryCandidate != null) {
        return primaryCandidate;
    }
    //ii. 根据@Priority取优先级最高的Bean
    String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
    if (priorityCandidate != null) {
        return priorityCandidate;
    }
    // iii. Fallback
    // 匹配依赖项的名字,要么是字段的名字,要么是set方法入参的名字
    for (Map.Entry<String, Object> entry : candidates.entrySet()) {
        String candidateName = entry.getKey();
        Object beanInstance = entry.getValue();
        //resolvableDependencies记录了某个类型对应某个Bean,启动Spring时会进行设置,比如BeanFactory.class对应beanFactory实例
        //注意:如果是Spring自己的byType,descriptor.getDependencyName()将返回空,只有是@Autowired才会返回方法属性名或方法参数名
        if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
                matchesBeanName(candidateName, descriptor.getDependencyName())) {
            return candidateName;
        }
    }
    return null;
}

i. 判断这些Bean中是否有@Primary标记的

org.springframework.beans.factory.support.DefaultListableBeanFactory#determinePrimaryCandidate

protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) {
    String primaryBeanName = null;
    //遍历所有候选bean
    for (Map.Entry<String, Object> entry : candidates.entrySet()) {
        String candidateBeanName = entry.getKey();
        Object beanInstance = entry.getValue();
        //判断是否有@Primary标记
        if (isPrimary(candidateBeanName, beanInstance)) {
            if (primaryBeanName != null) {
                //发现primaryBean存在多个,进一步判断

                //新发现的这个是不是在当前工厂中定义的
                boolean candidateLocal = containsBeanDefinition(candidateBeanName);
                //上一个发现的是不是在当前工厂中定义的
                boolean primaryLocal = containsBeanDefinition(primaryBeanName);
                //如果存在多个@Primary Bean在当前工厂中,则会抛异常
                if (candidateLocal && primaryLocal) {
                    throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
                            "more than one 'primary' bean found among candidates: " + candidates.keySet());
                }
                //有可能之前找到的@Primary是在父工厂,肯定优先取当前工厂中的Bean
                else if (candidateLocal) {
                    primaryBeanName = candidateBeanName;
                }
            }
            else {
                primaryBeanName = candidateBeanName;
            }
        }
    }
    return primaryBeanName;
}

判断是否有@Primary标记:

protected boolean isPrimary(String beanName, Object beanInstance) {
    //获取规范BeanName
    String transformedBeanName = transformedBeanName(beanName);
    if (containsBeanDefinition(transformedBeanName)) {
        //根据BeanDefinition判断是否是Primary
        return getMergedLocalBeanDefinition(transformedBeanName).isPrimary();
    }
    //当前工厂不存在这个BeanDefinition,则判断父工厂
    BeanFactory parent = getParentBeanFactory();
    return (parent instanceof DefaultListableBeanFactory &&
            ((DefaultListableBeanFactory) parent).isPrimary(transformedBeanName, beanInstance));
}

ii. 根据@Priority取优先级最高的Bean

org.springframework.beans.factory.support.DefaultListableBeanFactory#determineHighestPriorityCandidate

protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) {
    String highestPriorityBeanName = null;
    Integer highestPriority = null;
    //遍历所有候选Bean
    for (Map.Entry<String, Object> entry : candidates.entrySet()) {
        String candidateBeanName = entry.getKey();
        Object beanInstance = entry.getValue();
        if (beanInstance != null) {
            //获取当前Bean的优先级,解析的是@Priority注解
            Integer candidatePriority = getPriority(beanInstance);
            if (candidatePriority != null) {
                if (highestPriorityBeanName != null) {
                    //与之前优先级最高的进行比较
                    
                    //优先级相同则抛异常
                    if (candidatePriority.equals(highestPriority)) {
                        throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
                                "Multiple beans found with the same priority ('" + highestPriority +
                                "') among candidates: " + candidates.keySet());
                    }
                    //比较优先级,数字越小优先级越高
                    else if (candidatePriority < highestPriority) {
                        //记录新的最高优先级
                        highestPriorityBeanName = candidateBeanName;
                        highestPriority = candidatePriority;
                    }
                }
                else {
                    //第一次记录最高优先级
                    highestPriorityBeanName = candidateBeanName;
                    highestPriority = candidatePriority;
                }
            }
        }
    }
    return highestPriorityBeanName;
}

解析@Priority注解:

protected Integer getPriority(Object beanInstance) {
    //依赖注入用的排序比较器
    Comparator<Object> comparator = getDependencyComparator();
    if (comparator instanceof OrderComparator) {
        //获取优先级
        return ((OrderComparator) comparator).getPriority(beanInstance);
    }
    return null;
}

OrderComparator默认实现是AnnotationAwareOrderComparator
org.springframework.core.annotation.AnnotationAwareOrderComparator#getPriority

public Integer getPriority(Object obj) {
    if (obj instanceof Class) {
        //从类上获取@Priority的value值
        return OrderUtils.getPriority((Class<?>) obj);
    }
	//obj也有可能是实例
    Integer priority = OrderUtils.getPriority(obj.getClass());
    if (priority == null  && obj instanceof DecoratingProxy) {
        //如果obj是装饰类代理,则返回这个代理后面的(最终)装饰类
        //根据装饰类(代理背后真正的类)获取优先级
        return getPriority(((DecoratingProxy) obj).getDecoratedClass());
    }
    return priority;
}

org.springframework.core.annotation.OrderUtils#getPriority

public static Integer getPriority(Class<?> type) {
    //SearchStrategy.TYPE_HIERARCHY:执行整个类型层次结构的完整搜索,包括超类和实现的接口。
    //JAVAX_PRIORITY_ANNOTATION="javax.annotation.Priority"
    //MergedAnnotation.VALUE="value"
    return MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).get(JAVAX_PRIORITY_ANNOTATION)
            .getValue(MergedAnnotation.VALUE, Integer.class).orElse(null);
}

iii. 匹配依赖项的名字

// Fallback
// 匹配依赖项的名字,要么是字段的名字,要么是set方法入参的名字
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
    String candidateName = entry.getKey();
    Object beanInstance = entry.getValue();
    //resolvableDependencies记录了某个类型对应某个Bean实例(启动Spring时会进行设置,比如BeanFactory.class对应beanFactory实例)
    //注意:如果是Spring自己的byType,descriptor.getDependencyName()将返回空,只有是@Autowired才会返回字段属性名或方法参数名
    if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
            matchesBeanName(candidateName, descriptor.getDependencyName())) {
        return candidateName;
    }
}

resolvableDependencies:类似于一个缓存,事先指定了类和实例的映射关系,只要是注入这个类型,就用这个类型对应的实例进行注入
在这里插入图片描述

获取依赖项名字:
org.springframework.beans.factory.config.DependencyDescriptor#getDependencyName

public String getDependencyName() {
    //字段类型,直接field.getName
    return (this.field != null ? this.field.getName() : obtainMethodParameter().getParameterName());
}

//org.springframework.core.MethodParameter#getParameterName
public String getParameterName() {
    if (this.parameterIndex < 0) {
        return null;
    }
    //方法参数类型,则用参数名字发现器
    ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer;
    if (discoverer != null) {
        String[] parameterNames = null;
        //解析方法的入参名
        if (this.executable instanceof Method) {
            parameterNames = discoverer.getParameterNames((Method) this.executable);
        }
        //解析构造函数的入参名
        else if (this.executable instanceof Constructor) {
            parameterNames = discoverer.getParameterNames((Constructor<?>) this.executable);
        }
        if (parameterNames != null) {
            this.parameterName = parameterNames[this.parameterIndex];
        }
        this.parameterNameDiscoverer = null;
    }
    return this.parameterName;
}

候选BeanName 和 依赖项name匹配:
org.springframework.beans.factory.support.DefaultListableBeanFactory#matchesBeanName

protected boolean matchesBeanName(String beanName, @Nullable String candidateName) {
    //getAliases(beanName):获取beanName所有的别名
    return (candidateName != null &&
            (candidateName.equals(beanName) || ObjectUtils.containsElement(getAliases(beanName), candidateName)));
}

i. 记录匹配过的BeanName

注意这个集合,以字段注入为例,方法注入同理:
在这里插入图片描述
在解析依赖项的时候,当找到需要注入的Bean后,会把Bean的名字放到这个集合里:
在这里插入图片描述
等全部找完以后,会记录当前Bean,依赖了这些Bean
在这里插入图片描述

以前讲DependsOn时说过,并且销毁Bean时也会用到。

j. 筛选出来的是Class

有可能筛选出来的是某个bean的类型,此处就进行实例化,调用getBean
因为依赖注入过程中,没必要把所有候选Bean都实例化
后续流程最多只会注入一个,保证注入的那个实例化过就OK了
而且后续判断是否匹配,有Class就够了

org.springframework.beans.factory.config.DependencyDescriptor#resolveCandidate

public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
        throws BeansException {
    return beanFactory.getBean(beanName);
}

k:NullBean

这样配置就是一个NullBean,不是null
在这里插入图片描述

最后

以上就是狂野小白菜为你收集整理的Spring源码分析(十)依赖注入源码解析3:DefaultListableBeanFactory#doResolveDependency 真正开始解析依赖项4.2 真正开始解析依赖项(最核心方法)a. 依赖注入的缓存b. 获取@Value所指定的值c. 占位符填充(${})d. 解析Spring表达式(#{})e. 将value转换为descriptor所对应的类型f. 注入多实例情况g. 根据类型查找所有候选Beanh. 如果根据类型匹配到了多个Beani. 记录匹配过的BeanNamej.的全部内容,希望文章能够帮你解决Spring源码分析(十)依赖注入源码解析3:DefaultListableBeanFactory#doResolveDependency 真正开始解析依赖项4.2 真正开始解析依赖项(最核心方法)a. 依赖注入的缓存b. 获取@Value所指定的值c. 占位符填充(${})d. 解析Spring表达式(#{})e. 将value转换为descriptor所对应的类型f. 注入多实例情况g. 根据类型查找所有候选Beanh. 如果根据类型匹配到了多个Beani. 记录匹配过的BeanNamej.所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(58)

评论列表共有 0 条评论

立即
投稿
返回
顶部