關(guān)于@Qualifier("beanName")用法
@Qualifier("beanName")是什么?
@Qualifier 注解,正如其名(Qualifier 意為“限定符”、“修飾符”),它的核心作用是在依賴注入時(shí),提供更精確的篩選條件,幫助 Spring 從多個(gè)同類型的候選 Bean 中,準(zhǔn)確地“限定”出你想要的那一個(gè)。
@Primary 是在眾多選項(xiàng)中選出一個(gè)“默認(rèn)冠軍”,而 @Qualifier 則像是直接通過“身份證號”(Bean 的名字)來點(diǎn)名。
如何使用@Qualifier?
繼續(xù)我們之前的 NotificationService 例子。我們有兩個(gè) Bean:EmailNotificationService 和 SmsNotificationService。
第一步:為 Bean 命名
Spring 默認(rèn)會給 Bean 一個(gè)名字,通常是類名首字母小寫(如 emailNotificationService)。但為了更清晰,我們最好自己指定一個(gè)簡短的名字。
這可以通過 @Service("beanName") 或 @Component("beanName") 來實(shí)現(xiàn)。
import org.springframework.stereotype.Service;
@Service("emailNotifier") // 給這個(gè)Bean起一個(gè)限定名 "emailNotifier"
public class EmailNotificationService implements NotificationService {
// ...
}
import org.springframework.stereotype.Service;
@Service("smsNotifier") // 給這個(gè)Bean起一個(gè)限定名 "smsNotifier"
public class SmsNotificationService implements NotificationService {
// ...
}
現(xiàn)在,IoC 容器中有兩個(gè) NotificationService 類型的 Bean,它們分別被命名為 emailNotifier 和 smsNotifier。
第二步:在注入點(diǎn)使用 @Qualifier 進(jìn)行點(diǎn)名
現(xiàn)在,OrderService 可以明確地告訴 Spring 它想要哪一個(gè)實(shí)現(xiàn)。
- 場景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中,
// 我就要那個(gè)名字叫 "emailNotifier" 的!
this.notificationService = notificationService;
}
// ...
}
- 場景B:另一個(gè)服務(wù),需要短信通知
@Service
public class UrgentOrderService {
private final NotificationService notificationService;
@Autowired
public UrgentOrderService(@Qualifier("smsNotifier") NotificationService notificationService) {
// 這里明確指定了需要短信通知服務(wù)
this.notificationService = notificationService;
}
// ...
}
通過這種方式,@Qualifier 提供了極高的靈活性。
不同的消費(fèi)方可以根據(jù)自己的需求,注入同一個(gè)接口的不同實(shí)現(xiàn),而無需修改 Bean 定義方的代碼。
正面對決:@Primaryvs@Qualifier,誰的優(yōu)先級更高?
答案非常明確:@Qualifier 的優(yōu)先級更高。
可以這樣理解它們的邏輯關(guān)系:
Spring 的注入邏輯
1.首先按類型查找:找到所有類型為 NotificationService 的 Bean。
2.發(fā)現(xiàn)多個(gè)候選者:emailNotificationService 和 smsNotificationService。
3.檢查是否有 @Qualifier 精確指定:
- 如果有(比如
@Qualifier("smsNotifier")),Spring 就會忽略其他所有因素(包括@Primary),直接選擇名為smsNotifier的 Bean。@Qualifier的指令是絕對的。 - 如果沒有
@Qualifier,Spring 才會繼續(xù)下一步。
4.檢查是否有 @Primary 默認(rèn)選項(xiàng):
- 在剩下的候選者中,尋找被
@Primary標(biāo)記的 Bean。 - 如果找到了,就注入那個(gè)
@Primary的 Bean。 - 如果沒有找到
@Primary的 Bean(也沒有@Qualifier),Spring 就會再次陷入困惑,拋出NoUniqueBeanDefinitionException。
我們用一個(gè)比喻來描述
你去一家快餐店點(diǎn)漢堡。
@Primary:菜單上,“招牌牛肉漢堡”旁邊印著一個(gè)大大的 “本店推薦” 標(biāo)志。@Qualifier:你對服務(wù)員說的話。
場景1:只使用 @Primary
- 你對服務(wù)員說:“來個(gè)漢堡。”(相當(dāng)于
@Autowired NotificationService service;) - 服務(wù)員看到菜單上的“本店推薦”,就直接給你拿了“招牌牛肉漢堡”。
場景2:@Primary 和 @Qualifier 同時(shí)存在
- 菜單上“招牌牛肉漢堡”依然是“本店推薦”(
@Primary)。 - 但你對服務(wù)員說:“我不要推薦的,給我來一個(gè)‘香辣雞腿堡’。”(相當(dāng)于
@Autowired @Qualifier("spicyChickenBurger") Burger burger;) - 服務(wù)員會聽你的話,而不是看菜單的推薦。你的直接指令(
@Qualifier)優(yōu)先級更高。
代碼示例驗(yàn)證優(yōu)先級
@Service("emailNotifier")
@Primary // Email服務(wù)是首選
public class EmailNotificationService implements NotificationService { ... }
@Service("smsNotifier")
public class SmsNotificationService implements NotificationService { ... }
// --- 消費(fèi)者 ---
@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() {
// 這將調(diào)用 SmsNotificationService
notificationService.sendNotification("您的訂單已成功創(chuàng)建!");
}
}
在這個(gè)例子中,最終被注入到 OrderService 的是 SmsNotificationService,完美驗(yàn)證了 @Qualifier 的更高優(yōu)先級。
總結(jié)
| 特性 | @Primary | @Qualifier("beanName") |
|---|---|---|
| 角色 | 設(shè)置全局默認(rèn)值 | 進(jìn)行局部精確指定 |
| 決定權(quán) | Bean 的提供方 | Bean 的消費(fèi)方 |
| 優(yōu)先級 | 較低 | 較高 |
| 使用時(shí)機(jī) | 當(dāng)多個(gè)實(shí)現(xiàn)中有一個(gè)是絕大多數(shù)情況下的選擇時(shí)。 | 當(dāng)需要靈活地在多個(gè)實(shí)現(xiàn)之間切換,或者需要覆蓋 @Primary 的默認(rèn)行為時(shí)。 |
@Primary 和 @Qualifier 是 Spring IoC 中一對相輔相成的利器,共同解決了依賴注入中的歧義性問題,使得代碼既能保持簡潔(依賴于默認(rèn)),又能擁有足夠的靈活性(按需指定)。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java的JSON格式轉(zhuǎn)換庫GSON的初步使用筆記
GSON是Google開發(fā)并在在GitHub上開源的Java對象與JSON互轉(zhuǎn)功能類庫,在Android開發(fā)者中也大受歡迎,這里我們就來看一下Java的JSON格式轉(zhuǎn)換庫GSON的初步使用筆記:2016-06-06
idea2020.1最新版永久破解/pycharm也可用(步驟詳解)
這篇文章主要介紹了idea2020.1最新版永久破解/pycharm也可用,本文給大家分享簡單實(shí)現(xiàn)步驟,通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04
詳解springMVC獲取前端請求的數(shù)據(jù)與三個(gè)作用域
文章介紹了Spring MVC中獲取前端請求數(shù)據(jù)的多種方式,包括使用@RequestParam注解、@RequestHeader注解和@CookieValue注解,以及處理請求中文亂碼的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2026-02-02

