Java 實用注解篇之@Qualifier 深度解析及實戰(zhàn)案例
前言
在 Spring 框架中,@Qualifier
是一個常見的注解,主要用于 解決依賴注入(DI)時的歧義性。當一個接口有多個實現(xiàn)類時,Spring 無法自動決定該注入哪個具體的 Bean,此時 @Qualifier
可以幫助我們 指定要注入的 Bean 名稱。
一、@Qualifier 的作用
1?? 解決 Spring 依賴注入沖突
當有多個 Bean 可用于注入時,Spring 需要知道應該選擇哪一個:
- 如果沒有
@Qualifier
,Spring 會拋出 NoUniqueBeanDefinitionException。 - 使用
@Qualifier
,可以明確指定要注入的 Bean。
2?? @Qualifier 基本使用
示例:多個相同類型的 Bean 時,Spring 無法自動選擇
@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(); } }
此時運行時會報錯:
NoUniqueBeanDefinitionException: No qualifying bean of type 'Animal' available
因為 Dog
和 Cat
都實現(xiàn)了 Animal
,Spring 不知道該注入哪個。
? 解決方案:使用 @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
這個 Bean,避免了沖突。
二、@Qualifier 源碼解析
1?? @Qualifier 注解的定義
Spring 框架中的 @Qualifier
是一個 標準注解,定義如下:
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Qualifier { String value(); }
可以看到:
@Target
允許它用于 字段、參數(shù)、方法和類。@Retention(RetentionPolicy.RUNTIME)
讓它在 運行時生效。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 并進行注入。
三、@Qualifier 實戰(zhàn)案例
1?? @Qualifier 結合 @Autowired
如果有多個 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 結合 @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 結合 @Primary
如果希望默認注入某個 Bean,但仍然允許 @Qualifier
選擇其他 Bean,可以結合 @Primary
:
@Component @Primary public class DefaultAnimal implements Animal { @Override public void speak() { System.out.println("我是默認動物!"); } }
@Service public class AnimalService { @Autowired private Animal animal; // 默認注入 DefaultAnimal @Autowired @Qualifier("dog") private Animal dog; // 指定注入 Dog }
? animal
默認注入 DefaultAnimal
,dog
注入 Dog
,兩者互不干擾。
四、@Qualifier 使用注意事項
? 1. @Qualifier 不能用于構造方法
? 錯誤示例
@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 { } // ? 不要同時使用 @Primary 和 @Qualifier
@Primary
和 @Qualifier
邏輯上是沖突的,應該 只使用一個 來指定注入。
? 3. @Qualifier 必須匹配 Bean 名稱
如果 @Qualifier("dogBean")
,但 Bean 名稱是 "dog"
,會導致找不到 Bean:
@Autowired @Qualifier("dogBean") // ? 錯誤 private Animal animal;
Spring 需要 @Qualifier("dog")
才能正確注入。
五、總結
重點 | 說明 |
---|---|
@Qualifier | 解決多個 Bean 注入沖突,指定具體 Bean |
@Qualifier + @Autowired | 選擇特定 Bean 進行注入 |
@Qualifier + @Bean | 在 @Configuration 中手動指定 Bean |
@Primary + @Qualifier | 默認注入 @Primary ,但可以用 @Qualifier 覆蓋 |
注意事項 | @Qualifier 必須匹配 Bean 名稱,避免和 @Primary 沖突 |
六、思考與拓展
@Qualifier
能否和@Lazy
結合使用?@Qualifier
在 Spring Boot@Conditional
配置中的應用?@Qualifier
結合 Spring AOP 是否有特殊用法?
到此這篇關于Java 實用注解篇之@Qualifier 深度解析及實戰(zhàn)案例的文章就介紹到這了,更多相關Java 注解@Qualifier 內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
詳解mybatis-plus使用@EnumValue注解的方式對枚舉類型的處理
這篇文章主要介紹了詳解mybatis-plus使用@EnumValue注解的方式對枚舉類型的處理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-12-12SpringBoot+ShardingSphereJDBC實現(xiàn)讀寫分離詳情
這篇文章主要介紹了SpringBoot+ShardingSphereJDBC實現(xiàn)讀寫分離詳情,通過用??MySQL??進行一主一從的主從復制展開全文內容,需要的朋友可以參考一下2022-08-085分鐘快速學會spring boot整合Mybatis的方法
這篇文章主要給大家介紹了如何通過5分鐘快速學會spring boot整合Mybatis的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用spring boot具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2019-12-12