深入理解 Spring 中的 @Primary 与 @Qualifier

一、背景

在 Spring / Spring Boot 项目中,经常会遇到同一个接口有多个实现类的情况。例如:

  • Mysql 实现

  • MongoDB 实现

  • Redis 实现

当使用@Autowired注入时,Spring 默认是按类型注入(By Type)

如果容器中存在多个同类型 Bean,就会出现:

NoUniqueBeanDefinitionException

为了解决这个问题,Spring 提供了两个核心注解:

  • @Primary

  • @Qualifier

本文将系统讲解它们的作用、优先级以及实际项目中的最佳实践,并提供一个可运行的 Spring Boot 示例项目


二、@Primary 注解

1. 作用

@Primary用来指定默认 Bean

当存在多个相同类型 Bean 时,如果某个 Bean 标记为@Primary,Spring 在自动注入时会优先选择它。

2. 示例

@Component @Primary public class MysqlMessageService implements MessageService { @Override public String send() { return "Message from MySQL service"; } }
@Component public class EmailMessageService implements MessageService { @Override public String send() { return "Message from Email service"; } }

注入:

@Autowired private MessageService messageService;

运行结果:

Message from MySQL service

因为MysqlMessageService被标记为@Primary


三、@Qualifier 注解

1. 作用

@Qualifier用于显式指定要注入的 Bean 名称

当存在多个 Bean 时,可以精准指定需要的实现。

2. 示例

@Autowired @Qualifier("emailMessageService") private MessageService messageService;

运行结果:

Message from Email service

四、Spring Bean 注入优先级

Spring 在解析@Autowired时的大致流程:

  1. 按类型查找 Bean

  2. 如果多个 Bean

  3. 优先选择@Primary

  4. 如果仍然冲突

  5. 尝试按字段名匹配

  6. 最终无法确定则抛出异常

优先级总结:

@Qualifier ↓ @Primary ↓ 字段名匹配

因此:

  • @Qualifier优先级最高

  • @Primary负责默认实现


五、最佳实践

推荐在实际项目中:

1️⃣ 使用@Primary指定系统默认实现

2️⃣ 使用@Qualifier指定特殊实现

3️⃣ 避免依赖字段名自动匹配

示例:

@Primary DefaultUserService
@Qualifier("redisUserService")

这样可以让代码更加清晰、可维护性更高


六、总结

@Primary@Qualifier是 Spring 解决多实现类依赖注入问题的核心机制。

注解作用
@Primary指定默认 Bean
@Qualifier指定具体 Bean

理解它们的注入优先级,对于开发大型 SpringBoot 项目非常重要。


如果这篇文章对你有帮助,欢迎收藏或分享。

本文的参考代码链接已经开源,地址:https://github.com/LetMyTearsFlow/SpringBootGuide/tree/main/PrimaryQualifier

如果对你有帮助,欢迎点击Star收藏,后续的SpringBoot代码示例都会在这里更新。