1. 概述
今天帶你了解一下 Spring 框架中的 @Qualifier
注解,它解決了哪些問題,以及如何使用它。我們還將了解它與 @Primary
注解的不同之處。更多的技術解析請訪問 felord.cn
2. 痛點
使用 @Autowired
注解是 Spring 依賴注入的絕好方法。但是有些場景下僅僅靠這個注解不足以讓Spring知道到底要注入哪個 bean。
默認情況下,@Autowired
按類型裝配 Spring Bean。
如果容器中有多個相同類型的 bean,則框架將拋出 NoUniqueBeanDefinitionException
, 以提示有多個滿足條件的 bean 進行自動裝配。程序無法正確做出判斷使用哪一個,下面就是個鮮活的例子:
@Component("fooFormatter")
public class FooFormatter implements Formatter {
public String format() {
return "foo";
}
}
@Component("barFormatter")
public class BarFormatter implements Formatter {
public String format() {
return "bar";
}
}
@Component
public class FooService {
@Autowired
private Formatter formatter;
//todo
}
如果我們嘗試將 FooService
加載到我們的上下文中,Spring 框架將拋出 NoUniqueBeanDefinitionException
。這是因為 Spring 不知道要注入哪個 bean。為了避免這個問題,有幾種解決方案。那么我們本文要講解的 @Qualifier
注解就是其中之一。跟着小胖哥的節奏往下走。
3. @Qualifier
通過使用 @Qualifier
注解,我們可以消除需要注入哪個 bean 的問題。讓我們重新回顧一下前面的例子,看看我們如何通過包含 @Qualifier
注釋來指出我們想要使用哪個 bean 來解決問題:
@Component
public class FooService {
@Autowired
@Qualifier("fooFormatter")
private Formatter formatter;
//todo
}
通過將 @Qualifier
注解與我們想要使用的特定 Spring bean 的名稱一起進行裝配,Spring 框架就能從多個相同類型並滿足裝配要求的 bean 中找到我們想要的,避免讓Spring腦裂。我們需要做的是@Component或者@Bean注解中聲明的value屬性以確定名稱。
其實我們也可以在 Formatter
實現類上使用 @Qualifier
注釋,而不是在 @Component
或者 @Bean
中指定名稱,也能達到相同的效果:
@Component
@Qualifier("fooFormatter")
public class FooFormatter implements Formatter {
public String format() {
return "foo";
}
}
@Component
@Qualifier("barFormatter")
public class BarFormatter implements Formatter {
public String format() {
return "bar";
}
}
4. @Qualifier VS @Primary
還有另一個名為 @Primary
的注解,我們也可以用來發生依賴注入的歧義時決定要注入哪個 bean。當存在多個相同類型的 bean 時,此注解定義了首選項。除非另有說明,否則將使用與 @Primary
注釋關聯的 bean 。
我們來看一個例子:
@Bean
public Employee tomEmployee() {
return new Employee("Tom");
}
@Bean
@Primary
public Employee johnEmployee() {
return new Employee("john");
}
在此示例中,兩個方法都返回相同的 Employee
類型。Spring 將注入的 bean 是方法 johnEmployee
返回的 bean。這是因為它包含 @Primary
注解。當我們想要指定默認情況下應該注入特定類型的 bean 時,此注解很有用。
如果我們在某個注入點需要另一個 bean,我們需要專門指出它。我們可以通過 @Qualifier
注解來做到這一點。例如,我們可以通過使用 @Qualifier
注釋來指定我們想要使用 tomEmployee
方法返回的 bean 。
值得注意的是,如果 @Qualifier
和 @Primary
注釋都存在,那么 @Qualifier
注釋將具有優先權。基本上,@Primary
是定義了默認值,而 @Qualifier
則非常具體。
當然@Component
也可以使用@Primary
注解,這次使用的還是上面3的示例:
@Component
@Primary
public class FooFormatter implements Formatter {
public String format() {
return "foo";
}
}
@Component
public class BarFormatter implements Formatter {
public String format() {
return "bar";
}
}
在這種情況下,@Primary
注解指定了默認注入的是 FooFormatter
,消除了場景中的注入歧義。
5. 通過名稱來自動注入
在使用 @Autowired
進行自動裝配時,如果 Spring 沒有其他提示,將會按照需要注入的變量名稱來尋找合適的 bean。也可以解決依賴注入歧義的問題。讓我們看一些基於我們最初的例子的代碼:
@Component
public class FooService {
@Autowired
private Formatter fooFormatter;
//todo
}
在這種情況下,Spring 將確定要注入的 bean 是 FooFormatter
,因為字段名稱與我們在該 bean 的 @Component
或者 @Bean
注解中使用的值(默認 @Bean
使用方法名)相匹配。
6. 總結
通過對 @Qualifier
的探討,我們知道該注解是用來消除依賴注入沖突的。這種在日常開發,比如 Rabbtimq 的隊列聲明中很常見。小胖哥也通過該注解和其他上述注解的組合使用和對比中展示了一些常用的用法。這將有助於你對 Spring 的依賴注入機制的了解。
關注公眾號:Felordcn獲取更多資訊