1. 问题分析
当我们使用 Spring 的时候,有时候会遇到下面这种情况。
假设我有 A、B 两个类,在 A 中注入 B,如下:
@Component
public class A {
@Autowired
B b;
}
至于 B,则在配置类中存在多个实例:
@Configuration
@ComponentScan
public class JavaConfig {
@Bean("b1")
B b1() {
return new B();
}
@Bean("b2")
B b2() {
return new B();
}
}
这样的项目启动之后,必然会抛出如下异常:
当然,对于这样的问题,相信有经验的同学都知道该怎么解决:
-
可以使用 @Resource 注解,使用该注解时指定具体的 Bean 名称即可。
-
在 @Autowired 注解之上,再多加一个 @Qualifier("b1") 注解,通过该注解去指定要加载的 Bean 名称。
@Component
public class A {
@Autowired
@Qualifier("b1")
B b;
}
3.在多个 B 对象的某一个之上,添加 @Primary 注解,表示当存在重复的 B 对象时,优先使用哪一个。
@Configuration
@ComponentScan
public class JavaConfig {
@Bean("b1")
@Primary
B b1() {
return new B();
}
@Bean("b2")
B b2() {
return new B();
}
}
这里三个方法,其中 @Resource 是 JSR 中提供的注解,我这里先不展开,松哥后面专门再来和大家聊 @Resource 注解的注入原理。今天我主要是想和小伙伴们分享一下后面两种方案的实现原理。
上面大致介绍了这个方法的执行思路,接下来我们就来看一下执行细节。
2. 源码解析
2.1 doResolveDependency
给 A 注入 B 的时候,会调用到 doResolveDependency 方法,我们再来看下该方法:
DefaultListableBeanFactory#doResolveDependency:
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
//...
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}