当前位置: 首页 > news >正文

@Primary 是做什么的?

简单来说,@Primary 的作用是:当 IoC 容器中存在多个相同类型的 Bean 时,告诉 Spring 在进行依赖注入时,优先选择被 @Primary 标记的那个。


让我们用一个比喻来解释:默认收货地址

想象一下你在购物网站(比如淘宝或京东)的账户里保存了多个收货地址:

  • 地址A:你家的地址
  • 地址B:你公司的地址
  • 地址C:你父母家的地址

当你下单时,网站需要知道把货送到哪里。如果你不指定,系统就会很困惑:“我到底该用哪个地址?” 这时就会出错。

@Primary 就相当于你把“地址A(你家)”设置为了“默认收货地址”。

  • 默认情况:你下单时,网站会自动选用你家的地址。
  • 特殊情况:如果你这次想把东西寄到公司,你就需要在下单时明确地选择“地址B”。

在 Spring 的世界里:

  • 收货地址 -> Bean 的实现
  • 下单 -> 进行 @Autowired 依赖注入
  • 系统困惑 -> Spring 抛出 NoUniqueBeanDefinitionException 异常
  • 设置默认地址 (@Primary) -> 标记一个 Bean 为首选
  • 明确选择其他地址 (@Qualifier) -> 使用 @Qualifier 注解指定想要的 Bean

问题场景:没有 @Primary 会发生什么?

假设我们有一个通知服务,它既可以通过邮件发送,也可以通过短信发送。

1. 定义接口

public interface NotificationService {void sendNotification(String message);
}

2. 两个实现类

@Service // 这是一个Bean
public class EmailNotificationService implements NotificationService {@Overridepublic void sendNotification(String message) {System.out.println("通过邮件发送通知: " + message);}
}@Service // 这也是一个Bean,和上面那个类型相同
public class SmsNotificationService implements NotificationService {@Overridepublic void sendNotification(String message) {System.out.println("通过短信发送通知: " + message);}
}

3. 在其他地方注入

@Service
public class OrderService {private final NotificationService notificationService;@Autowired // Spring在这里犯了难!public OrderService(NotificationService notificationService) {this.notificationService = notificationService;}public void placeOrder() {// ...下单逻辑...notificationService.sendNotification("您的订单已成功下单!");}
}

当你启动这个应用时,Spring 会立即报错:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.myapp.NotificationService' available: expected single matching bean but found 2: emailNotificationService,smsNotificationService

错误原因:Spring 在尝试为 OrderService 注入 NotificationService 时,发现容器里有两个符合条件的 Bean(EmailNotificationServiceSmsNotificationService)。它不知道该选哪一个,所以只能抛出异常。


解决方案:使用 @Primary

现在,假设我们系统的主要通知方式是邮件。我们可以把 EmailNotificationService 标记为首选。

@Service
@Primary // <<-- 加上这个注解
public class EmailNotificationService implements NotificationService {// ...
}

其他代码完全不变。现在再次启动应用,一切正常!

OrderService 需要 NotificationService 时,Spring 再次发现有两个候选者。但这次,它看到 EmailNotificationService 身上有 @Primary 标记,于是它毫不犹豫地选择了这个 Bean 进行注入。


@Primary vs @Qualifier

@Qualifier 是解决同样问题的另一种方式,但它们的侧重点不同。

特性@Primary@Qualifier("beanName")
解决方式“默认”机制。在众多候选者中指定一个为首选。“指定”机制。明确告诉 Spring 我要哪一个。
注解位置写在 Bean 的定义类上。(@Service, @Component旁边)写在 注入点上。(@Autowired旁边)
影响范围全局性。所有不明确指定的注入都会默认使用它。局部性。只对当前这一个注入点有效。
代码侵入性对使用者透明,使用者不需要知道有多个实现。使用者必须知道具体 Bean 的名字,并修改注入代码。

什么时候用哪个?

  • 使用 @Primary:当你的实现中有一个是明确的、常用的、默认的选项时。比如,90% 的情况都用邮件通知,只有个别特殊场景用短信。这时将邮件服务设为 @Primary 是最优雅的。

  • 使用 @Qualifier:当多个实现没有主次之分,它们是平等的,使用者必须根据业务场景显式地选择一个时。或者,当你需要在一个特定地方覆盖 @Primary 的默认行为时。

覆盖 @Primary 的例子:

@Service
public class HighPriorityAlertService {private final NotificationService notificationService;@Autowired// 即使EmailService是@Primary,我这里也明确指定要用SmsServicepublic HighPriorityAlertService(@Qualifier("smsNotificationService") NotificationService notificationService) {this.notificationService = notificationService;}public void sendAlert() {notificationService.sendNotification("!!系统紧急警报!!");}
}

在这个例子中,即使 EmailNotificationService 是首选,HighPriorityAlertService 依然通过 @Qualifier 精确地注入了 SmsNotificationService

总结

@Primary 是一个强大而优雅的工具,用于解决依赖注入中的歧义性问题。它通过在 Bean 定义端设立一个“默认选项”,使得注入端的代码可以保持干净和通用,是实现“约定优于配置”思想的一个绝佳体现。

http://www.dtcms.com/a/286736.html

相关文章:

  • CAD 约束求解:核心技术原理、流程及主流框架快速解析
  • A33-vstar笔记及资料分享:搭建交叉编译环境
  • 动态规划 + DFS + 记忆化!Swift 解 LeetCode 329 的实战笔记
  • 实战指南|智慧无人机安防系统搭建全流程解析
  • 记录DataGrip 2025.1.3破解失败后,无法重启问题修复
  • centos7安装MySQL8.4手册
  • Hive数据仓库工具
  • 甲状腺结节TI-RADS分类的多目标分类头任务深度学习模型评估报告
  • go语言学习之包
  • 新书推介 | 吉林大学出版教材《汽车智能辅助驾驶系统技术》,国产仿真工具链GCKontrol-GCAir教学应用
  • Python_2
  • math.h函数
  • 弱网测试
  • 跨域问题及解决方案
  • ChatGPT Agent:统一端到端Agentic模型的技术革新与行业影响
  • React + Mermaid 图表渲染消失问题剖析及 4 种代码级修复方案
  • 前端-CSS盒模型、浮动、定位、布局
  • 前端迟迟收不到响应,登录拦截器踩坑!
  • 比较含距离和顺序的结构相似性
  • 【EPLAN 2.9】许可证xx成功却显示红色叉,无法启动
  • 人工智能时代对高精尖人才的需求分析
  • 嵌入式数据结构之顺序表总结
  • openpyxl 流式读取xlsx文件(read_only=true)读不到sheet页中所有行
  • 配置本地git到gitlab并推送
  • 【机器学习】AdamW可调参数介绍及使用说明
  • 【LINUX操作系统】ssh远程连接---客户端Windows连接服务端虚拟机
  • 应用集成体系深度解析:从数据互通到流程协同
  • 你需要了解的 AI 智能体设计模式
  • compose multiplatform 常用库
  • Python FastMCP:让你的AI工具链飞起来