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 的上下文环境还没有被加载,所以不可能为静态变量绑定值。同时,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 实现了它)。
我们拿 AutowiredAnnotationBeanPostProcessor 举下例子,看下它的这个方法做了什么:
他会扫描正在实例化的 bean 上的 @Autowired 和 @Value 注解,扫描到就会把对应的方法或者属性封装起来,最终封装成InjectionMetadata对象。
看一下 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 是怎么进行依赖注入的呢,先看下是什么时候调用到的:
以 AutowiredFieldElement(InjectedElement 的其中一个实现) 为例:
这部分内容分为三块:
首先,会先判断这个对象是不是@Value注解的,如果是就是去执行value解析,解析出value的值直接返回,如下就是value的处理:
如果不是@Value的话,那么就进入到解析bean的过程,下面这个是解析多重bean的,即依赖注入的是个集合:
接着如果不是多重bean对象,则会去匹配单个的bean;如果匹配到多个的话就会通过一种策略(如优先级【Ordered接口】或者 @Primary)去决策哪个bean来注入。
tag1:1270 行 findAutowireCandidates() 方法
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()
我们先看下解析 Optional 的方法
关于 ObjectProvider 是什么可以先看下这篇文章:https://www.jianshu.com/p/0c36fa57e2d4
通过看 DependencyObjectProvider 代码的实现,其实就是对 DependencyDescriptor 的一些妙用罢了。