@Primary用于解决多实现类注入歧义,标记首选Bean,仅作用于Bean定义处,与@Qualifier共存时后者优先。

当一个接口有多个实现类,Spring 容器在自动注入时无法确定该选哪一个,就会抛出 NoUniqueBeanDefinitionException。@Primary 的作用就是明确告诉 Spring:“如果没有特别指定,就用我这个”。它不改变 Bean 的创建逻辑,只影响注入时的默认选择。
什么时候必须用 @Primary?
典型场景包括:
- 同一接口在不同环境有不同实现(比如生产用 MySQL Repository,本地用内存版)
- 策略模式中多个策略类实现同一接口(如支付方式:支付宝、微信、银联)
- 多数据源配置下多个
DataSource或TransactionManager - 自定义线程池(
TaskExecutor)存在多个定义时
@Primary 怎么加才有效?
只能标注在 Bean 的定义位置,不是注入点:
- 加在
@Component、@Service、@Repository等组件类上 - 加在
@Bean方法上(常用于配置类中) - 不能加在
@Autowired字段或构造参数上——那是@Qualifier的职责
例如:
@Service<br>@Primary<br>public class AliyunSmsService implements SmsService { ... }
或:
@Configuration<br>public class SmsConfig {<br> @Bean<br> @Primary<br> public SmsService aliyunSmsService() {<br> return new AliyunSmsService();<br> }<br>}
@Primary 和 @Qualifier 谁优先?
两者可以共存,且 @Qualifier 优先级更高:
- 没写
@Qualifier时,Spring 自动选@Primary标记的 Bean - 写了
@Qualifier("xxx"),哪怕那个 Bean 没标@Primary,也会被选中 - 如果多个 Bean 都标了
@Primary,Spring 仍会报错——它只允许一个“首选”
常见踩坑点
容易忽略但很关键的细节:
-
不能和 @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) 混用:代理对象可能绕过
@Primary判定 -
配合 @Profile 使用要小心:比如
@Profile("prod") @Primary在非 prod 环境下不生效,若其他 profile 下没有@Primary,仍可能报错 -
第三方 Starter 自动配置的 Bean 也可能带 @Primary:比如 Spring Boot 的
DataSource默认 Bean 就标了@Primary,你自定义时需注意冲突 -
类路径重复扫描导致同名 Bean 冲突:此时加
@Primary只能缓解,根源是@ComponentScan范围重叠

















