个人公众号:IT周瑜,十二年Java开发和架构经验,一年大模型应用开发经验,爱好研究源码,比如Spring全家桶源码、MySQL源码等,同时也喜欢分享技术干货,期待你的关注
最近闲着的时候在看Spring 6.2的源码,发现了一些新特性,比如本文要介绍的@Fallback注解。
相信大家都知道@Primary注解,而@Fallback相当于是@Primary的反向补充。
Spring在进行依赖注入时,会根据属性的类型去Spring容器中匹配Bean,但有可能根据类型找到了多个Bean,并且也无法根据属性名匹配到Bean时,就会报错,比如expected single matching bean but found 2
,此时,就可以利用@Primary来解决。
加了@Primary的Bean表示是同类型多个Bean中的主Bean,换句话说,如果Spring根据类型找到了多个Bean,会选择其中加了@Primary的Bean来进行注入,因此,同类型的多个Bean中只能有一个加了@Primary,如果有多个也会报错more than one 'primary' bean found
。
比如以下代码会使用orderService1来进行注入:
@Bean
@Primary
public OrderService orderService1() {
return new OrderService();
}
@Bean
public OrderService orderService2() {
return new OrderService();
}
而加了@Fallback注解的Bean为**备选Bean,**比如以下代码会使用orderService2来进行依赖注入:
@Bean
@Fallback
public OrderService orderService1() {
return new OrderService();
}
@Bean
public OrderService orderService2() {
return new OrderService();
}
因为orderService1加了@Fallback注解,相当于备胎,只有当没有其他Bean可用时,才会用orderService1这个备胎,有其他Bean就会优先用其他Bean。
@Primary和@Fallback都是用在依赖注入时根据类型找到了多个Bean的场景中:
- @Primary比较强势,它在说:“直接用我就可以了,不用管其他Bean”
- @Fallback比较弱势,它在说:“先别用我,先用其他Bean”
如果根据类型只找到一个Bean就用不着他两了,另外,同类型多个Bean中@Primary的Bean只能有一个,但可以有多个@Fallback。
大家觉得@Fallback注解怎么样?
实际上,@Primary和@Fallback两个注解的源码实现在同一个方法中,源码及注释如下,感兴趣的同学可以看看:
protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) {
String primaryBeanName = null;
// First pass: identify unique primary candidate
// 先找@Primary注解的Bean
// candidates就是根据类型找到的多个Bean,key为beanName, Value为bean对象
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateBeanName = entry.getKey();
Object beanInstance = entry.getValue();
if (isPrimary(candidateBeanName, beanInstance)) {
if (primaryBeanName != null) {
boolean candidateLocal = containsBeanDefinition(candidateBeanName);
boolean primaryLocal = containsBeanDefinition(primaryBeanName);
// 找到多个@Primary会报错
if (candidateLocal == primaryLocal) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
"more than one 'primary' bean found among candidates: " + candidates.keySet());
}
else if (candidateLocal) {
primaryBeanName = candidateBeanName;
}
}
else {
// 找到一个@Primary注解的Bean就先存着,看是不是还有其他@Primay注解的Bean
primaryBeanName = candidateBeanName;
}
}
}
// Second pass: identify unique non-fallback candidate
// 没有@Primary注解的Bean情况下,才找没有加@Fallback注解的,加了@Fallback注解的Bean会被过滤掉
if (primaryBeanName == null) {
for (String candidateBeanName : candidates.keySet()) {
// 判断是否没有加@Fallback
if (!isFallback(candidateBeanName)) {
// 如果有多个Bean没有加@Fallback,会返回null,后续会根据属性名从多个bean中进行匹配,匹配不到就会报错
if (primaryBeanName != null) {
return null;
}
primaryBeanName = candidateBeanName;
}
}
}
return primaryBeanName;
}