Java 實(shí)用注解篇之@Qualifier 深度解析及實(shí)戰(zhàn)案例
前言
在 Spring 框架中,@Qualifier 是一個(gè)常見的注解,主要用于 解決依賴注入(DI)時(shí)的歧義性。當(dāng)一個(gè)接口有多個(gè)實(shí)現(xiàn)類時(shí),Spring 無法自動(dòng)決定該注入哪個(gè)具體的 Bean,此時(shí) @Qualifier 可以幫助我們 指定要注入的 Bean 名稱。
一、@Qualifier 的作用
1?? 解決 Spring 依賴注入沖突
當(dāng)有多個(gè) Bean 可用于注入時(shí),Spring 需要知道應(yīng)該選擇哪一個(gè):
- 如果沒有
@Qualifier,Spring 會拋出 NoUniqueBeanDefinitionException。 - 使用
@Qualifier,可以明確指定要注入的 Bean。
2?? @Qualifier 基本使用
示例:多個(gè)相同類型的 Bean 時(shí),Spring 無法自動(dòng)選擇
@Component
public class Dog implements Animal {
@Override
public void speak() {
System.out.println("汪汪!");
}
}
@Component
public class Cat implements Animal {
@Override
public void speak() {
System.out.println("喵喵!");
}
}@Service
public class AnimalService {
private final Animal animal;
@Autowired
public AnimalService(Animal animal) {
this.animal = animal;
}
public void makeSound() {
animal.speak();
}
}此時(shí)運(yùn)行時(shí)會報(bào)錯(cuò):
NoUniqueBeanDefinitionException: No qualifying bean of type 'Animal' available
因?yàn)?Dog 和 Cat 都實(shí)現(xiàn)了 Animal,Spring 不知道該注入哪個(gè)。
? 解決方案:使用 @Qualifier 指定具體 Bean
@Service
public class AnimalService {
private final Animal animal;
@Autowired
public AnimalService(@Qualifier("dog") Animal animal) {
this.animal = animal;
}
public void makeSound() {
animal.speak();
}
}這樣 AnimalService 只會注入 dog 這個(gè) Bean,避免了沖突。
二、@Qualifier 源碼解析
1?? @Qualifier 注解的定義
Spring 框架中的 @Qualifier 是一個(gè) 標(biāo)準(zhǔn)注解,定義如下:
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Qualifier {
String value();
}可以看到:
@Target允許它用于 字段、參數(shù)、方法和類。@Retention(RetentionPolicy.RUNTIME)讓它在 運(yùn)行時(shí)生效。String value()方法表示指定的 Bean 名稱。
2?? Spring 解析 @Qualifier
Spring 在 AutowiredAnnotationBeanPostProcessor 中解析 @Qualifier:
if (methodParameter.hasParameterAnnotation(Qualifier.class)) {
String beanName = methodParameter.getParameterAnnotation(Qualifier.class).value();
bean = beanFactory.getBean(beanName, methodParameter.getParameterType());
}解析過程:
- 檢查
@Qualifier是否存在,如果存在就獲取value()。 - 根據(jù)
value()找到 Bean 并進(jìn)行注入。
三、@Qualifier 實(shí)戰(zhàn)案例
1?? @Qualifier 結(jié)合 @Autowired
如果有多個(gè) Bean,使用 @Qualifier 指定注入的 Bean:
@Component("catBean")
public class Cat implements Animal {
@Override
public void speak() {
System.out.println("喵喵!");
}
}
@Component("dogBean")
public class Dog implements Animal {
@Override
public void speak() {
System.out.println("汪汪!");
}
}@Service
public class AnimalService {
@Autowired
@Qualifier("dogBean")
private Animal animal;
public void makeSound() {
animal.speak();
}
}? AnimalService 只會注入 dogBean,避免 NoUniqueBeanDefinitionException。
2?? @Qualifier 結(jié)合 @Bean
如果 Bean 是通過 @Bean 方法創(chuàng)建的,也可以使用 @Qualifier 指定:
@Configuration
public class AnimalConfig {
@Bean
@Qualifier("bigDog")
public Animal bigDog() {
return new Dog();
}
@Bean
@Qualifier("smallDog")
public Animal smallDog() {
return new Dog();
}
}@Service
public class AnimalService {
@Autowired
@Qualifier("bigDog")
private Animal animal;
}? 這樣可以選擇 bigDog 而不是 smallDog。
3?? @Qualifier 結(jié)合 @Primary
如果希望默認(rèn)注入某個(gè) Bean,但仍然允許 @Qualifier 選擇其他 Bean,可以結(jié)合 @Primary:
@Component
@Primary
public class DefaultAnimal implements Animal {
@Override
public void speak() {
System.out.println("我是默認(rèn)動(dòng)物!");
}
}@Service
public class AnimalService {
@Autowired
private Animal animal; // 默認(rèn)注入 DefaultAnimal
@Autowired
@Qualifier("dog")
private Animal dog; // 指定注入 Dog
}? animal 默認(rèn)注入 DefaultAnimal,dog 注入 Dog,兩者互不干擾。
四、@Qualifier 使用注意事項(xiàng)
? 1. @Qualifier 不能用于構(gòu)造方法
? 錯(cuò)誤示例
@Service
public class AnimalService {
private final Animal animal;
@Autowired
public AnimalService(@Qualifier("dog") Animal animal) { // ? 無效
this.animal = animal;
}
}? 正確方式
@Service
public class AnimalService {
private final Animal animal;
@Autowired
public AnimalService(@Qualifier("dogBean") Animal animal) { // ? 正確
this.animal = animal;
}
}? 2. @Qualifier 不能和 @Primary 沖突
@Component
@Primary
@Qualifier("dog")
public class Dog implements Animal { } // ? 不要同時(shí)使用 @Primary 和 @Qualifier@Primary 和 @Qualifier 邏輯上是沖突的,應(yīng)該 只使用一個(gè) 來指定注入。
? 3. @Qualifier 必須匹配 Bean 名稱
如果 @Qualifier("dogBean"),但 Bean 名稱是 "dog",會導(dǎo)致找不到 Bean:
@Autowired
@Qualifier("dogBean") // ? 錯(cuò)誤
private Animal animal;Spring 需要 @Qualifier("dog") 才能正確注入。
五、總結(jié)
| 重點(diǎn) | 說明 |
|---|---|
@Qualifier | 解決多個(gè) Bean 注入沖突,指定具體 Bean |
@Qualifier + @Autowired | 選擇特定 Bean 進(jìn)行注入 |
@Qualifier + @Bean | 在 @Configuration 中手動(dòng)指定 Bean |
@Primary + @Qualifier | 默認(rèn)注入 @Primary,但可以用 @Qualifier 覆蓋 |
| 注意事項(xiàng) | @Qualifier 必須匹配 Bean 名稱,避免和 @Primary 沖突 |
六、思考與拓展
@Qualifier能否和@Lazy結(jié)合使用?@Qualifier在 Spring Boot@Conditional配置中的應(yīng)用?@Qualifier結(jié)合 Spring AOP 是否有特殊用法?
到此這篇關(guān)于Java 實(shí)用注解篇之@Qualifier 深度解析及實(shí)戰(zhàn)案例的文章就介紹到這了,更多相關(guān)Java 注解@Qualifier 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Aop 如何獲取參數(shù)名參數(shù)值
這篇文章主要介紹了Spring Aop 如何獲取參數(shù)名參數(shù)值的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
使用@RequestBody配合@Valid校驗(yàn)入?yún)?shù)
這篇文章主要介紹了使用@RequestBody配合@Valid校驗(yàn)入?yún)?shù),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
了解Java虛擬機(jī)JVM的基本結(jié)構(gòu)及JVM的內(nèi)存溢出方式
這篇文章主要介紹了Java虛擬機(jī)JVM的基本結(jié)構(gòu)及JVM的內(nèi)存溢出方式,涉及到Java內(nèi)存分配相關(guān)方面的知識,需要的朋友可以參考下2016-01-01
MyBatis中的SQL映射文件配置結(jié)果映射的操作指南
MyBatis?是一款優(yōu)秀的?ORM?框架,它提供了多種配置方式來定義?SQL?語句以及結(jié)果映射規(guī)則,本文將介紹?MyBatis?中的?SQL?映射文件如何配置結(jié)果映射,包括常規(guī)類型、集合類型等多種情況,需要的朋友可以參考下2023-07-07
永中文檔在線轉(zhuǎn)換服務(wù)Swagger調(diào)用說明
這篇文章主要為大家介紹了永中文檔在線轉(zhuǎn)換服務(wù)Swagger調(diào)用說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Java的Struts2框架中攔截器使用的實(shí)例教程
攔截器是Struts框架的重要特性,Struts中每一個(gè)Action請求都包裝在一系列的攔截器的內(nèi)部,這里我們就來看一下Java的Struts2框架中攔截器使用的實(shí)例教程2016-07-07
MybatisPlus特殊查詢的實(shí)現(xiàn)介紹
這篇文章主要介紹了MybatisPlus查詢投影、聚合查詢、分組查詢、等值查詢、范圍查詢、模糊查詢、排序查詢,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-10-10
Java Switch對各類型支持實(shí)現(xiàn)原理
這篇文章主要介紹了Java Switch對各類型支持實(shí)現(xiàn)原理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05

