这些天研究Spring源码,遇到一个问题始终想不明白,resolveDependency->doResolveDependency->findAutowireCandidates中有这样一段代码:
Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class<?> autowiringType = classObjectEntry.getKey();
// autowiringType是requiredType的父类或本身
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
请问这个if (autowiringType.isAssignableFrom(requiredType))的意义是什么?
为此我做了个试验:
首先创建A、A1、A2,A1继承A,A2继承A1,其中没有任何代码。
然后创建User类,只有一个成员变量A1 a1:
public class User {
@Autowired
private A1 a1;
public A1 getA1() {
return a1;
}
public void setA1(A1 a1) {
this.a1 = a1;
}
}
findAutowireCandidates.xml:
<bean class="A1" name="a1"/>
<bean class="A2" name="a2"/>
<bean class="findAutowireCandidates.User" name="user" autowire="byType"/>
<context:component-scan base-package="findAutowireCandidates"/>
这种情况下一定会报异常,因为User类a1在自动注入的时候会有多个bean与之匹配,为了避免这种情况产生可以使用@Primary等方法,但那些不是要讨论的主题,这里用另一个方法,自定义一个BeanFactoryPostProcessor,向resolvableDependencies中注册一个A2:
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
configurableListableBeanFactory.registerResolvableDependency(A2.class,new A2());
}
}
最后写个main方法:
public class TestFindAutowireCandidates {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("findAutowireCandidates.xml");
}
}
最后运行,会发现依然报错,原因依然是User的a1有多个bean与之匹配:a1、a2,接着对MyBeanFactoryPostProcessor做如下修改:
configurableListableBeanFactory.registerResolvableDependency(A.class,new A2());
把key改成A.class,再运行就不会报错了,而且User的a1注入的不是a1、a2,而是MyBeanFactoryPostProcessor中这个new出来的A2对象。
以上实验纠其原因,就是开头提到的这个if (autowiringType.isAssignableFrom(requiredType)),这个if的意思是如果autowiringType是requiredType的本身或其父类,才可以进来。
findAutowireCandidates这个方法的大概意思就是要找到与requiredType类型匹配的所有候选bean,先在resolvableDependencies中查找,再从容器中所有bean中查找。后者我没什么问题,主要是前者,为什么在resolvableDependencies中查找时,如果autowiringType是requiredType的子类会被筛选掉呢?也就是前面试验中第一种报错的情况:如果我在resolvableDependencies中注册A2.class,new A2()这个键值对,由于A2是A1的子类,这里就会被筛选掉,导致这个MyBeanFactoryPostProcessor写了跟没写一样;但如果你注册的是A.class,new A2()就会生效。
但是为啥会这么写呢?如果没有这个if (autowiringType.isAssignableFrom(requiredType))不是也OK么?直接判断if (requiredType.isInstance(autowiringValue))不就可以了?请明白的赐教!
谈不上什么清除明白,只是在看见这个问题之后来兴趣了去翻了下源码,有兴趣可以讨论。
先说你第一种注入方式,我这里是通过了的。但它很明显不是从这个比较中获取的,是从上面的
BeanFactoryUtils.beanNamesForTypeIncludingAncestors
中获取的两个候选者,在下面的foreach中,全部加入在后续方法determineAutowireCandidate
中决定,这里决定的因素是名称相同。在说
registerResolvableDependency
并不是特别为
@Autowired
准备的,从代码中也能看出 a1,a2,new A2 是全部加入了,在determineAutowireCandidate
中,谁最先符合条件,就返回谁,这里的haspMap是linkedHaspMap ,在resolvableDependencies
中?,名称相同? 而registerResolvableDependency
那个是最先加入的,且符合resolvableDependencies.containsValue()
所以返回了。最后说,这条判断是很有必要的,如果要获取申明的依赖对象,则获取的key 应该是其父类或者自己,这很符合byType的逻辑。