关于@Qualifier("beanName")用法

 更新时间:2025年09月04日 09:51:03   作者:冰糖心书房  
@Qualifier用于精确指定Bean,@Primary设为默认,两者共存时,@Qualifier优先级更高,可灵活选择具体实现,解决依赖注入歧义,兼顾简洁与可配置性

@Qualifier("beanName")是什么?

@Qualifier 注解,正如其名(Qualifier 意为“限定符”、“修饰符”),它的核心作用是在依赖注入时,提供更精确的筛选条件,帮助 Spring 从多个同类型的候选 Bean 中,准确地“限定”出你想要的那一个。

@Primary 是在众多选项中选出一个“默认冠军”,而 @Qualifier 则像是直接通过“身份证号”(Bean 的名字)来点名。

如何使用@Qualifier?

继续我们之前的 NotificationService 例子。我们有两个 Bean:EmailNotificationServiceSmsNotificationService

第一步:为 Bean 命名

Spring 默认会给 Bean 一个名字,通常是类名首字母小写(如 emailNotificationService)。但为了更清晰,我们最好自己指定一个简短的名字。

这可以通过 @Service("beanName")@Component("beanName") 来实现。

import org.springframework.stereotype.Service;

@Service("emailNotifier") // 给这个Bean起一个限定名 "emailNotifier"
public class EmailNotificationService implements NotificationService {
    // ...
}
import org.springframework.stereotype.Service;

@Service("smsNotifier") // 给这个Bean起一个限定名 "smsNotifier"
public class SmsNotificationService implements NotificationService {
    // ...
}

现在,IoC 容器中有两个 NotificationService 类型的 Bean,它们分别被命名为 emailNotifiersmsNotifier

第二步:在注入点使用 @Qualifier 进行点名

现在,OrderService 可以明确地告诉 Spring 它想要哪一个实现。

  • 场景A:需要邮件通知
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class OrderService {
    private final NotificationService notificationService;

    @Autowired
    public OrderService(@Qualifier("emailNotifier") NotificationService notificationService) {
        // @Qualifier说:在所有NotificationService类型的Bean中,
        // 我就要那个名字叫 "emailNotifier" 的!
        this.notificationService = notificationService;
    }
    // ...
}
  • 场景B:另一个服务,需要短信通知
@Service
public class UrgentOrderService {
    private final NotificationService notificationService;

    @Autowired
    public UrgentOrderService(@Qualifier("smsNotifier") NotificationService notificationService) {
        // 这里明确指定了需要短信通知服务
        this.notificationService = notificationService;
    }
    // ...
}

通过这种方式,@Qualifier 提供了极高的灵活性。

不同的消费方可以根据自己的需求,注入同一个接口的不同实现,而无需修改 Bean 定义方的代码。

正面对决:@Primaryvs@Qualifier,谁的优先级更高?

答案非常明确:@Qualifier 的优先级更高。

可以这样理解它们的逻辑关系:

Spring 的注入逻辑

1.首先按类型查找:找到所有类型为 NotificationService 的 Bean。

2.发现多个候选者emailNotificationServicesmsNotificationService

3.检查是否有 @Qualifier 精确指定

  • 如果有(比如 @Qualifier("smsNotifier")),Spring 就会忽略其他所有因素(包括 @Primary),直接选择名为 smsNotifier 的 Bean。@Qualifier 的指令是绝对的。
  • 如果没有 @Qualifier,Spring 才会继续下一步。

4.检查是否有 @Primary 默认选项

  • 在剩下的候选者中,寻找被 @Primary 标记的 Bean。
  • 如果找到了,就注入那个 @Primary 的 Bean。
  • 如果没有找到 @Primary 的 Bean(也没有 @Qualifier),Spring 就会再次陷入困惑,抛出 NoUniqueBeanDefinitionException

我们用一个比喻来描述

你去一家快餐店点汉堡。

  • @Primary:菜单上,“招牌牛肉汉堡”旁边印着一个大大的 “本店推荐” 标志。
  • @Qualifier:你对服务员说的话。

场景1:只使用 @Primary

  • 你对服务员说:“来个汉堡。”(相当于 @Autowired NotificationService service;
  • 服务员看到菜单上的“本店推荐”,就直接给你拿了“招牌牛肉汉堡”。

场景2:@Primary@Qualifier 同时存在

  • 菜单上“招牌牛肉汉堡”依然是“本店推荐”(@Primary)。
  • 但你对服务员说:“我不要推荐的,给我来一个‘香辣鸡腿堡’。”(相当于 @Autowired @Qualifier("spicyChickenBurger") Burger burger;
  • 服务员会听你的话,而不是看菜单的推荐。你的直接指令(@Qualifier)优先级更高。

代码示例验证优先级

@Service("emailNotifier")
@Primary // Email服务是首选
public class EmailNotificationService implements NotificationService { ... }

@Service("smsNotifier")
public class SmsNotificationService implements NotificationService { ... }

// --- 消费者 ---
@Service
public class OrderService {
    private final NotificationService notificationService;

    @Autowired
    public OrderService(@Qualifier("smsNotifier") NotificationService notificationService) {
        // 尽管Email是@Primary,但这里通过@Qualifier明确指定了smsNotifier
        this.notificationService = notificationService;
    }

    public void placeOrder() {
        // 这将调用 SmsNotificationService
        notificationService.sendNotification("您的订单已成功创建!");
    }
}

在这个例子中,最终被注入到 OrderService 的是 SmsNotificationService,完美验证了 @Qualifier 的更高优先级。

总结

特性@Primary@Qualifier("beanName")
角色设置全局默认值进行局部精确指定
决定权Bean 的提供方Bean 的消费方
优先级较低较高
使用时机当多个实现中有一个是绝大多数情况下的选择时。当需要灵活地在多个实现之间切换,或者需要覆盖 @Primary 的默认行为时。

@Primary@Qualifier 是 Spring IoC 中一对相辅相成的利器,共同解决了依赖注入中的歧义性问题,使得代码既能保持简洁(依赖于默认),又能拥有足够的灵活性(按需指定)。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java的JSON格式转换库GSON的初步使用笔记

    Java的JSON格式转换库GSON的初步使用笔记

    GSON是Google开发并在在GitHub上开源的Java对象与JSON互转功能类库,在Android开发者中也大受欢迎,这里我们就来看一下Java的JSON格式转换库GSON的初步使用笔记:
    2016-06-06
  • java将图片至暗的实现方法

    java将图片至暗的实现方法

    下面小编就为大家带来一篇java将图片至暗的实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • idea2020.1最新版永久破解/pycharm也可用(步骤详解)

    idea2020.1最新版永久破解/pycharm也可用(步骤详解)

    这篇文章主要介绍了idea2020.1最新版永久破解/pycharm也可用,本文给大家分享简单实现步骤,通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • Java读取String分行字符串的方法

    Java读取String分行字符串的方法

    今天小编就为大家分享一篇Java读取String分行字符串的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07
  • java事件处理模型知识点总结

    java事件处理模型知识点总结

    在本篇文章里小辫给大家分享的是一篇关于java事件处理模型知识点总结内容,有兴趣的朋友们可以学习下。
    2021-01-01
  • 详解springMVC获取前端请求的数据与三个作用域

    详解springMVC获取前端请求的数据与三个作用域

    文章介绍了Spring MVC中获取前端请求数据的多种方式,包括使用@RequestParam注解、@RequestHeader注解和@CookieValue注解,以及处理请求中文乱码的方法,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2026-02-02
  • java实现倾斜水印铺满整张图

    java实现倾斜水印铺满整张图

    这篇文章主要为大家详细介绍了java实现倾斜水印铺满整张图的具体代码,教大家如何控制水印之间的空隙,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • Spring Boot 文件上传原理解析

    Spring Boot 文件上传原理解析

    Spring Boot 文件上传原理其实就是Spring MVC,因为这部分工作是Spring MVC做的而不是Spring Boot,那么,SpringMVC又是怎么处理文件上传这个过程的呢?下面通过本文给大家详细介绍下,一起看看吧
    2018-03-03
  • Java 定时任务技术趋势详情

    Java 定时任务技术趋势详情

    这篇文章主要介绍了Java 定时任务技术趋势详情,定时任务是每个业务常见的需求,比如每分钟扫描超时支付的订单,每小时清理一次数据库历史数据,每天统计前一天的数据并生成报表等,下文更多相关资料,需要的小伙伴可以参考一下
    2022-05-05
  • Java page cache回写机制案例详解

    Java page cache回写机制案例详解

    这篇文章主要介绍了Java page cache回写机制案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09

最新评论