程序员社区

Spring —— AutowiredAnnotationBeanPostProcessor 解析


title: Spring —— AutowiredAnnotationBeanPostProcessor 解析
subTiltle: @Value 和 @Autowired 注解进行 DI 的奥秘
date: 2020/11/18 14:48


引言

有一个同事写了如下代码问我为啥没有办法把 aaa 注入,我只知道静态的字段是不会被 Spring 依赖注入的,但是不知道为什么,所以决定研究一下。

@Component
public class Test01 {

    @Value("${test01.aaa}")
    private static String aaa;

    public void func() {
        System.out.println(aaa);
    }

}

答案是 Spring 在扫描类中的元数据信息的时候把静态的方法和字段给排除了。那么为啥 Spring 要排除 static 的字段和方法呢?

Spring —— AutowiredAnnotationBeanPostProcessor 解析插图

静态变量是属于类本身的信息,当类加载器加载静态变量时,Spring 的上下文环境还没有被加载,所以不可能为静态变量绑定值。同时,Spring也不鼓励为静态变量注入值(言外之意:并不是不能注入),因为它认为这会增加了耦合度,对测试不友好。

源码解析

本部分采用的代码

@Component
public class Test01 {

    @Value("${test01.aaa1}")
    private static String aaa1;

    @Value("${test01.aaa}")
    private String aaa2;

    @Autowired
    private Animal animal;

    @Autowired
    private List<Animal> animalList;

    public void func() {
        System.out.println(aaa2);
    }

}

我们首先看一下 Spring 是在什么时候调用 MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition() 方法,这个方法主要是对接下来依赖注入需要的一些元数据进行准备(CommonAnnotationBeanPostProcessor 和 AutowiredAnnotationBeanPostProcessor 实现了它)。

Spring —— AutowiredAnnotationBeanPostProcessor 解析插图1

我们拿 AutowiredAnnotationBeanPostProcessor 举下例子,看下它的这个方法做了什么:

他会扫描正在实例化的 bean 上的 @Autowired 和 @Value 注解,扫描到就会把对应的方法或者属性封装起来,最终封装成InjectionMetadata对象。

Spring —— AutowiredAnnotationBeanPostProcessor 解析插图2
Spring —— AutowiredAnnotationBeanPostProcessor 解析插图3
Spring —— AutowiredAnnotationBeanPostProcessor 解析插图4
Spring —— AutowiredAnnotationBeanPostProcessor 解析插图5

看一下 InjectionMetadata#EMPTY:

public class InjectionMetadata {
        
    public static final InjectionMetadata EMPTY = new InjectionMetadata(Object.class, Collections.emptyList()) {
        @Override
        protected boolean needsRefresh(Class<?> clazz) {
            return false;
        }
        @Override
        public void checkConfigMembers(RootBeanDefinition beanDefinition) {
        }
        @Override
        public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) {
        }
        @Override
        public void clear(@Nullable PropertyValues pvs) {
        }
    };
    
    。。。

他将当前类的所有方法都变成了空实现,当调用的时候不会做任何事(吐槽:为啥不用接口呢)

接下来我们来看下 AutowiredAnnotationBeanPostProcessor 是怎么进行依赖注入的呢,先看下是什么时候调用到的:

Spring —— AutowiredAnnotationBeanPostProcessor 解析插图6
Spring —— AutowiredAnnotationBeanPostProcessor 解析插图7
Spring —— AutowiredAnnotationBeanPostProcessor 解析插图8

以 AutowiredFieldElement(InjectedElement 的其中一个实现) 为例:

Spring —— AutowiredAnnotationBeanPostProcessor 解析插图9
Spring —— AutowiredAnnotationBeanPostProcessor 解析插图10

这部分内容分为三块:

首先,会先判断这个对象是不是@Value注解的,如果是就是去执行value解析,解析出value的值直接返回,如下就是value的处理:

Spring —— AutowiredAnnotationBeanPostProcessor 解析插图11

如果不是@Value的话,那么就进入到解析bean的过程,下面这个是解析多重bean的,即依赖注入的是个集合:

Spring —— AutowiredAnnotationBeanPostProcessor 解析插图12
Spring —— AutowiredAnnotationBeanPostProcessor 解析插图13

接着如果不是多重bean对象,则会去匹配单个的bean;如果匹配到多个的话就会通过一种策略(如优先级【Ordered接口】或者 @Primary)去决策哪个bean来注入。

Spring —— AutowiredAnnotationBeanPostProcessor 解析插图14
Spring —— AutowiredAnnotationBeanPostProcessor 解析插图15

tag1:1270 行 findAutowireCandidates() 方法

Spring —— AutowiredAnnotationBeanPostProcessor 解析插图16
Spring —— AutowiredAnnotationBeanPostProcessor 解析插图17

tag2: 1282 行 determineAutowireCandidate() 方法

protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
    Class<?> requiredType = descriptor.getDependencyType();
    //根据@Primary注解来择取最优解
    String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
    if (primaryCandidate != null) {
        return primaryCandidate;
    }
    //根据@Order,@PriorityOrder,及实现Order接口的序号来择取最优解
    String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
    if (priorityCandidate != null) {
        return priorityCandidate;
    }
    // Fallback
    for (Map.Entry<String, Object> entry : candidates.entrySet()) {
        String candidateName = entry.getKey();
        Object beanInstance = entry.getValue();
        //如果通过以上两步都不能选择出最优解,则使用最基本的策略
        //1. 首先如果这个类型已经由Spring注册过依赖关系对,则直接使用注册的对象,候选者集合是LinkedHashMap,有序Map集合,容器注册的依赖对象位于LinkedHashMap的起始位置
        //2. 如果没有注册过此类型的依赖关系,则根据属性的名称来匹配,如果属性名称和某个候选者的Bean名称或别名一致,那么直接将此Bean作为最优解
        if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
                matchesBeanName(candidateName, descriptor.getDependencyName())) {
            return candidateName;
        }
    }
    return null;
}

我们逐一分析这几个步骤,先看第一个,根据@Primary注解来择取最优解

protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) {
    String primaryBeanName = null;
    for (Map.Entry<String, Object> entry : candidates.entrySet()) {
        String candidateBeanName = entry.getKey();
        Object beanInstance = entry.getValue();
        //候选者可以是父容器内的标识了@Primary的Bean,也可以是当前容器的。SpringMVC容器将Spring容器作为父容器
        if (isPrimary(candidateBeanName, beanInstance)) {
            if (primaryBeanName != null) {
                boolean candidateLocal = containsBeanDefinition(candidateBeanName);
                boolean primaryLocal = containsBeanDefinition(primaryBeanName);
                //此处确保同一个容器中同一个类型的多个Bean最多只有一个Bean标识了@Primary
                if (candidateLocal && primaryLocal) {
                    throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
                            "more than one 'primary' bean found among candidates: " + candidates.keySet());
                }
                //如果上一个@Primary的Bean是父容器的,则用当前容器的候选者覆盖之前的@Primary的Bean
                else if (candidateLocal) {
                    primaryBeanName = candidateBeanName;
                }
            }
            else {
                primaryBeanName = candidateBeanName;
            }
        }
    }
    return primaryBeanName;
}

接着看第二个,根据@Order,@PriorityOrder

protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) {
    String highestPriorityBeanName = null;
    Integer highestPriority = null;
    for (Map.Entry<String, Object> entry : candidates.entrySet()) {
        String candidateBeanName = entry.getKey();
        Object beanInstance = entry.getValue();
        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());
                }
                //使用优先级序号最小的Bean作为最优解
                else if (candidatePriority < highestPriority) {
                    highestPriorityBeanName = candidateBeanName;
                    highestPriority = candidatePriority;
                }
            }
            else {
                highestPriorityBeanName = candidateBeanName;
                highestPriority = candidatePriority;
            }
        }
    }
    return highestPriorityBeanName;
}

参考文章

Spring源码解析-AutowiredAnnotationBeanPostProcessor依赖注入

MergedBeanDefinitionPostProcessor和@Autowired,@Value的关系

Spring注解@Autowired源码分析

附:beanFactory#resolveDependency()

Spring —— AutowiredAnnotationBeanPostProcessor 解析插图18

我们先看下解析 Optional 的方法

Spring —— AutowiredAnnotationBeanPostProcessor 解析插图19

关于 ObjectProvider 是什么可以先看下这篇文章:https://www.jianshu.com/p/0c36fa57e2d4

通过看 DependencyObjectProvider 代码的实现,其实就是对 DependencyDescriptor 的一些妙用罢了。

赞(0) 打赏
未经允许不得转载:IDEA激活码 » Spring —— AutowiredAnnotationBeanPostProcessor 解析

一个分享Java & Python知识的社区