Spring Boot 中多个同类型 Bean 时需明确指定注入目标,常用方式有四种:①@Primary设默认候选;②@Qualifier按名精确匹配;③@Resource按名注入(Java原生);④@ConditionalOnProperty条件化加载。

当 Spring Boot 中一个接口有多个实现类(即多个同类型 Bean)时,Spring 默认无法决定该注入哪一个,会直接抛出 NoUniqueBeanDefinitionException。解决的关键不是“阻止报错”,而是**明确告诉容器:此时该选谁**。常用方式有四种,按推荐程度和适用场景区分如下:
@Primary 指定默认候选 Bean
适用于“大多数情况用 A,少数特殊场景才换 B”的兜底策略。
- 在首选实现类上加
@Primary注解,它会在所有同类型 Bean 中被优先选中 - 该注解不依赖名称或配置,只作用于自动注入(
@Autowired)场景 - 注意:
@Primary的优先级低于@Qualifier和@Resource(name="xxx"),也低于@ConditionalOnProperty等条件化加载逻辑
@Qualifier 配合 @Autowired 精确匹配
适用于运行时根据业务分支动态选择不同实现,比如支付策略、消息渠道等。
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 每个实现类用
@Component("payAlipay")或@Service("smsChannelA")显式指定 Bean 名称 - 注入处使用
@Autowired @Qualifier("payAlipay")明确指定名称 - 也可自定义
@Qualifier衍生注解(如@Alipay、@WechatPay),提升可读性和类型安全
@Resource 按名称注入(Java 原生)
适用于已有 Java EE 习惯、或需兼容老项目结构的团队。
- 直接写
@Resource(name = "emailSender"),Spring 会先按名称查找,找不到再按类型回退 - 若省略
name属性,则默认使用字段名作为 Bean 名(如private MessageSender smsSender;→ 查找名为smsSender的 Bean) - 不建议与
@Autowired混用在同一字段,会导致行为不可控
@ConditionalOnProperty 等条件化加载
适用于环境或配置驱动的 Bean 选择,比如开发/测试/生产启用不同实现。
- 在实现类上加
@ConditionalOnProperty(name = "message.sender.type", havingValue = "email") - 配合配置文件中的
message.sender.type=email控制是否注册该 Bean - 多个实现类可设置互斥条件,确保同一时刻只有一个生效,避免冲突
实际项目中常组合使用:用 @Primary 提供默认行为,用 @Qualifier 支持显式切换,再辅以 @ConditionalOnProperty 实现环境隔离。不需要写工厂类,也不必手动管理 List,Spring 容器本身就能完成精准路由。










