当注入的 Bean 存在冲突时,到底有多少种解决方案?松哥总结了五种!

开发 前端
根据 type 去查找相应的 Bean 的时候,找到了多个候选 Bean,所以才会报错,所以我们注册一个 Bean 的时候,可以设置该 Bean 不是候选 Bean,这个设置并不影响通过 name 注入一个 Bean。

当我们从 Spring 容器中“拉”取一个 Bean 回来的时候,可以按照名字去拉取,也可以按照类型去拉取,按照 BeanName 拉取的话,一般来说只要 BeanName 书写没有问题,都是没问题的。但是如果是按照类型去拉取,则可能会因为 Bean 存在多个实例从而导致失败。

在前面的文章中,松哥和小伙伴们分享了 @Primary、@Qualifier 注解在处理该问题时的一些具体的方案,但是都是零散的,今天咱们来把这些方案总结一下,顺便再来看看是否还存在其他方案?

1. 问题呈现

假设我有 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();
    }
}

这样的项目启动之后,必然会抛出如下异常:

图片图片

今天我们就来总结下这个问题的解决方案。

2. 解决方案分析

2.1 @Resource

使用 @Resource 注解,这个应该是大家最容易想到的方案之一,不过使用 @Resource 注解需要额外添加依赖:

<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>

加了依赖之后,现在就可以直接使用 @Resource 注解了:

@Service
public class A {
    @Resource(name = "b1")
    B b;
}

2.2 @Qualifier 指定 name

另一种方案就是搭配 @Qualifier 注解,通过该注解指定 Bean 的名称:

@Service
public class A {
    @Autowired
    @Qualifier("b1")
    B b;
}

2.3 @Qualifier 不指定 name

这种方案也是搭配 @Qualifier,但是并不指定 BeanName,而是在 B 注册和 A 中注入 B 的时候,分别标记一个 @Qualifier 注解:

@Service
public class A {
    @Autowired
    @Qualifier
    B b;
}

@Configuration
@ComponentScan
public class JavaConfig {

    @Bean
    @Qualifier
    B b1() {
        return new B();
    }

    @Bean
    B b2() {
        return new B();
    }

}

2.4 不作为候选 Bean

另外还有一种方案,就是在注册 Bean 的时候,告诉 Spring 容器,这个 Bean 在通过 type 进行注入的时候,不作为候选 Bean。

小伙伴们知道,在第一小节中报的错,原因就是因为根据 type 去查找相应的 Bean 的时候,找到了多个候选 Bean,所以才会报错,所以我们注册一个 Bean 的时候,可以设置该 Bean 不是候选 Bean,这个设置并不影响通过 name 注入一个 Bean。

具体配置如下:

Java 代码配置:

@Configuration
@ComponentScan
public class JavaConfig {

    @Bean(autowireCandidate = false)
    B b1() {
        return new B();
    }

    @Bean
    B b2() {
        return new B();
    }

}

autowireCandidate 属性就表示这个 Bean 不是一个候选 Bean。

XML 配置:

<bean class="org.javaboy.bean.p2.B" autowire-candidate="false"/>

autowire-candidate 属性表示当前 Bean 是否作为一个候选 Bean。

2.5 @Primary

差点把我们最常用的方案忘了。@Primary 表示当通过 type 注入的时候,如果当前 Bean 存在多个实例,则优先使用带有 @Primary 注解的 Bean。

@Service
public class A {
    @Autowired
    B b;
}

@Configuration
@ComponentScan
public class JavaConfig {

    @Bean
    @Primary
    B b1() {
        return new B();
    }

    @Bean
    B b2() {
        return new B();
    }

}

好啦,这就是松哥总结出来的 5 种方案,实际上,基于这五种,还能衍生出来一些方案,这就需要小伙伴们自行探索啦~

最后大家思考这样一问题:对于第一小节提出来的问题,如果同时使用 2.2 和 2.5 小节的方案,那么哪一个会生效呢?

责任编辑:武晓燕 来源: 江南一点雨
相关推荐

2012-03-29 09:57:06

jQuery

2018-06-14 21:03:41

数据库MySQL日志类型

2018-05-04 07:36:35

医疗行业物联网IoT

2023-04-14 14:54:29

2023-05-26 07:19:49

Spring声明式事务

2013-04-25 14:26:54

GridView

2022-09-27 09:43:08

物联网设备物联网

2022-03-09 18:09:47

前端CSS代码

2011-06-07 10:15:38

GNULinux

2019-09-10 10:46:24

微服务架构传统服务

2023-04-18 16:31:00

2021-04-21 21:04:42

内存场景泄露

2021-05-07 09:39:54

数据清洗方式

2010-01-12 12:15:25

SOA安全解决方案

2021-09-26 09:17:01

Python命令定时任务

2012-12-26 11:04:14

2010-09-10 12:59:33

DIV嵌套CSS

2010-09-09 15:45:15

IT认证

2021-04-06 22:52:04

加密货币比特币数字货币

2019-12-24 08:49:06

容器Docker网络
点赞
收藏

51CTO技术栈公众号