1. 概述
在本教程中,我們將探討@Qualifier 註解可以幫助我們解決什麼問題,以及如何使用它。
我們還將解釋它與 @Primary 註解以及通過名稱自動裝配的區別。
2. 自動注入需要消除歧義
<em>@Autowired</em> 註解是一種顯式地在 Spring 中指定依賴注入需求的有效方法。雖然它很有用,但也有一些用例,單獨使用此註解不足以讓 Spring 瞭解應該注入哪個 Bean。
默認情況下,Spring 通過類型來解析自動注入的條目。
如果容器中存在多個同類型的 Bean,框架將拋出 <em>NoUniqueBeanDefinitionException</em>,指示有多個 Bean 可供自動注入。
讓我們設想一個場景,其中存在兩個可能的候選 Bean 作為給定實例的 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;
}如果嘗試將 FooService 加載到我們的上下文中,Spring 框架將會拋出 NoUniqueBeanDefinitionException 異常。這是因為 Spring 不知道應該注入哪個 Bean。為了避免這個問題,有幾種解決方案,其中 @Qualifier 註解就是其中之一。
3. <em @Qualifier</em>> 註解
通過使用 <em @Qualifier</em>> 註解,我們可以消除注入哪個 Bean 的問題。
讓我們回顧一下我們之前的例子,看看如何通過包含 <em @Qualifier</em>> 註解來指示我們想要使用的 Bean:
public class FooService {
@Autowired
@Qualifier("fooFormatter")
private Formatter formatter;
}通過包含 @Qualifier 註解,以及我們希望使用的特定實現名稱(例如 Foo),在這個例子中,我們可以避免 Spring 在查找相同類型的多個 Bean 時產生歧義。
需要注意的是,用於使用的 qualifier 的名稱應與 @Component 註解中聲明的名稱相同。
此外,我們也可以在 Formatter 接口實現類上使用 @Qualifier 註解,而不是在它們的 @Component 註解中指定名稱,從而達到相同的效果:
@Component
@Qualifier("fooFormatter")
public class FooFormatter implements Formatter {
//...
}
@Component
@Qualifier("barFormatter")
public class BarFormatter implements Formatter {
//...
}
4. @Qualifier 與 @Primary
還有另一個註解叫做 @Primary,我們可以使用它來決定在存在依賴注入歧義時應該注入哪個 Bean。
這個註解 定義了在存在多個相同類型的 Bean 時,偏好。 帶有 @Primary 註解的 Bean 將在未另有指示的情況下被使用。
讓我們來看一個例子:
@Configuration
public class Config {
@Bean
public Employee johnEmployee() {
return new Employee("John");
}
@Bean
@Primary
public Employee tonyEmployee() {
return new Employee("Tony");
}
}在本示例中,這兩個方法都返回相同類型的 Employee。 Spring 將注入的 Bean 是由方法 tonyEmployee 返回的那個。 這是因為它包含了 @Primary 註解。 這個註解在我們需要指定某個類型的 Bean 應該默認被注入時非常有用。
如果我們在某個注入點需要使用其他的 Bean,則需要通過 @Qualifier 註解明確指定。 例如,我們可以通過使用 @Qualifier 註解來指定我們想要使用由 johnEmployee 方法返回的 Bean。
值得注意的是,如果同時使用了 @Qualifier 和 @Primary 註解,則 @Qualifier 註解將具有優先權。 基本上,@Primary 定義了一個默認值,而 @Qualifier 則非常具體。
讓我們再看一個使用 @Primary 註解的方法,這次使用之前的示例:
@Component
@Primary
public class FooFormatter implements Formatter {
//...
}
@Component
public class BarFormatter implements Formatter {
//...
}
在這種情況下,@Primary 註解放置在其中一個實現類中,將消除歧義。
5. @Qualifier 與通過名稱進行自動注入
當使用自動注入時,另一種選擇是使用字段名稱來注入。 這在沒有其他提示的情況下是默認設置。 讓我們基於我們之前的示例來看一些代碼:
public class FooService {
@Autowired
private Formatter fooFormatter;
}在這種情況下,Spring 會確定要注入的 Bean 是 FooFormatter,因為字段名與我們在 @Component 註解中為該 Bean 指定的值匹配。
6. 結論
在本文中,我們描述了需要消除歧義以確定要注入哪些 Bean 的場景。特別是,我們研究了 <em @Qualifier </em> 註解,並將其與確定需要使用的其他類似方法進行了比較。