Spring6新特性之:既生@Primary,何生@Fallback

个人公众号: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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值