1. 概述
從 Spring 2.5 版本開始,框架引入了基於註解的 依賴注入 (Dependency Injection) 功能。該功能的關鍵註解是 @Autowired。 它允許 Spring 解決並注入協作的 Bean 到我們的 Bean 中。
在本教程中,我們首先將瞭解如何啓用自動裝配以及 各種 自動裝配 Bean 的 方式。之後,我們將討論 使用 @Qualifier 註解解決 Bean 衝突,以及潛在的異常場景。
2. 啓用 @Autowired 註解
Spring 框架實現了自動依賴注入。換句話説,通過在 Spring 配置文件中聲明所有 Bean 的依賴關係,Spring 容器可以自動注入協作 Bean 之間的關係。 這種機制被稱為 Spring Bean 自動注入。
為了在我們的應用程序中使用基於 Java 的配置,讓我們啓用註解驅動的注入,以便加載我們的 Spring 配置:
@Configuration
@ComponentScan("com.baeldung.autowire.sample")
public class AppConfig {}或者,`
此外,。 此單一標註相當於使用 `
讓我們在應用程序的主類中使用此標註: 因此,當我們運行這個 Spring Boot 應用程序時,它會自動掃描當前包及其子包中的所有組件。@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}3. 使用 @Autowired
啓用註解注入後,我們可以使用自動裝配功能,應用於屬性、setter 方法和構造函數。
3.1. 使用 <em @Autowired 註解處理屬性
讓我們看看如何使用 <em @Autowired 註解來標註屬性。這消除了使用 getter 和 setter 的需求。
首先,讓我們定義一個 <em fooFormatter Bean:
@Component("fooFormatter")
public class FooFormatter {
public String format() {
return "foo";
}
}然後,我們將使用 FooService 注入該 Bean,在字段定義上使用 @Autowired:
@Component
public class FooService {
@Autowired
private FooFormatter fooFormatter;
}因此,Spring 在創建 fooFormatter 時會注入它。
3.2. 在 Setter 方法上使用 <em @Autowired>
現在,讓我們嘗試在 Setter 方法上添加 <em @Autowired> 註解。
在下面的示例中,當 FooService 被創建時,Setter 方法被調用,並傳入 FooFormatter 的實例:
public class FooService {
private FooFormatter fooFormatter;
@Autowired
public void setFormatter(FooFormatter fooFormatter) {
this.fooFormatter = fooFormatter;
}
}
3.3. 在構造函數中使用 <em @Autowired>
最後,讓我們在構造函數中使用 <em @Autowired>。
我們將看到 Spring 將 <em FooFormatter> 作為參數注入到 <em FooService> 的構造函數中。
public class FooService {
private FooFormatter fooFormatter;
@Autowired
public FooService(FooFormatter fooFormatter) {
this.fooFormatter = fooFormatter;
}
}4. @Autowired 和可選依賴項
當一個 Bean 正在被構建時,@Autowired 依賴項應該可用。否則,如果 Spring 無法解析 Bean 用於注入,它將拋出異常。
因此,它防止了 Spring 容器由於異常而無法成功啓動:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [com.autowire.sample.FooDAO] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations:
{@org.springframework.beans.factory.annotation.Autowired(required=true)}為了解決這個問題,我們需要聲明一個指定類型的Bean:
public class FooService {
@Autowired(required = false)
private FooDAO dataAccessor;
}5. 自動注入解析
默認情況下,Spring 通過類型解析 @Autowired 聲明。 如果容器中存在同類型的多個 Bean,框架將拋出致命異常。
為了解決此衝突,我們需要明確地告訴 Spring 我們想要注入哪個 Bean。
5.1. 通過 @Qualifier 進行自動注入
例如,讓我們看看如何使用 @Qualifier 註解來指定所需的 Bean。
首先,我們將定義 2 個類型為 Formatter 的 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";
}
}現在讓我們嘗試將 Formatter Bean 注入到 FooService 類中:
public class FooService {
@Autowired
private Formatter formatter;
}在我們的示例中,Spring 容器中提供了兩個具體的 <em >Formatter</em> 實現。因此,當構建 <em >FooService</em> 時,Spring 會拋出 <em >NoUniqueBeanDefinitionException</em> 異常:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type [com.autowire.sample.Formatter] is defined:
expected single matching bean but found 2: barFormatter,fooFormatter
我們可以通過縮小實現方式,使用 @Qualifier 註解來避免這種情況:
public class FooService {
@Autowired
@Qualifier("fooFormatter")
private Formatter formatter;
}當存在同類型的多個Bean時,建議使用 @Qualifier 以避免歧義。
請注意,@Qualifier 註解的值與我們的 FooFormatter 實現中的 @Component 註解中聲明的名稱相匹配。
5.2. 自定義配額自動注入
Spring 還允許我們創建自己的自定義 <em @Qualifier</em>> 註解。 要做到這一點,我們應該為 <em @Qualifier</em>> 註解提供定義:
@Qualifier
@Target({
ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface FormatterType {
String value();
}然後,我們可以使用 FormatterType 在各種實現中指定自定義值:
@FormatterType("Foo")
@Component
public class FooFormatter implements Formatter {
public String format() {
return "foo";
}
}@FormatterType("Bar")
@Component
public class BarFormatter implements Formatter {
public String format() {
return "bar";
}
}最後,我們的自定義 Qualifier 註解已準備好用於自動裝配:
@Component
public class FooService {
@Autowired
@FormatterType("Foo")
private Formatter formatter;
}
指定在 @Target 標記元註解中的值會限制標記的適用範圍,在我們的示例中,該範圍包括字段、方法、類型和參數。
5.3. 通過名稱自動注入
Spring 使用 Bean 的名稱作為默認的 qualifier 值。 它會檢查容器,查找與 property 屬性完全相同的 Bean。
因此,在我們的示例中,Spring 將 fooFormatter 屬性名稱與 FooFormatter 實現匹配。 因此,它在構造 FooService 時注入該特定實現。
public class FooService {
@Autowired
private Formatter fooFormatter;
}6. 結論
在本文中,我們討論了自動裝配及其使用方法。我們還研究瞭如何解決由於缺少 Bean 或歧義 Bean 注入引起的兩種常見自動裝配異常。