使用 @Autowired

JSR 330 的 @Inject 註解可以用於取代本節範例中 Spring 的 @Autowired 註解。更多詳細資訊,請參閱這裡

您可以將 @Autowired 註解應用於建構子,如下列範例所示

  • Java

  • Kotlin

public class MovieRecommender {

	private final CustomerPreferenceDao customerPreferenceDao;

	@Autowired
	public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
		this.customerPreferenceDao = customerPreferenceDao;
	}

	// ...
}
class MovieRecommender @Autowired constructor(
	private val customerPreferenceDao: CustomerPreferenceDao)

從 Spring Framework 4.3 開始,如果目標 Bean 只定義一個建構子,則不再需要在此類建構子上使用 @Autowired 註解。但是,如果有數個建構子可用,且沒有主要/預設建構子,則至少必須使用 @Autowired 註解其中一個建構子,以指示容器要使用哪一個。請參閱關於建構子解析的討論以取得詳細資訊。

您也可以將 @Autowired 註解應用於傳統 setter 方法,如下列範例所示

  • Java

  • Kotlin

public class SimpleMovieLister {

	private MovieFinder movieFinder;

	@Autowired
	public void setMovieFinder(MovieFinder movieFinder) {
		this.movieFinder = movieFinder;
	}

	// ...
}
class SimpleMovieLister {

	@set:Autowired
	lateinit var movieFinder: MovieFinder

	// ...

}

您也可以將註解應用於具有任意名稱和多個引數的方法,如下列範例所示

  • Java

  • Kotlin

public class MovieRecommender {

	private MovieCatalog movieCatalog;

	private CustomerPreferenceDao customerPreferenceDao;

	@Autowired
	public void prepare(MovieCatalog movieCatalog,
			CustomerPreferenceDao customerPreferenceDao) {
		this.movieCatalog = movieCatalog;
		this.customerPreferenceDao = customerPreferenceDao;
	}

	// ...
}
class MovieRecommender {

	private lateinit var movieCatalog: MovieCatalog

	private lateinit var customerPreferenceDao: CustomerPreferenceDao

	@Autowired
	fun prepare(movieCatalog: MovieCatalog,
				customerPreferenceDao: CustomerPreferenceDao) {
		this.movieCatalog = movieCatalog
		this.customerPreferenceDao = customerPreferenceDao
	}

	// ...
}

您可以將 @Autowired 應用於欄位,甚至可以將其與建構子混合使用,如下列範例所示

  • Java

  • Kotlin

public class MovieRecommender {

	private final CustomerPreferenceDao customerPreferenceDao;

	@Autowired
	private MovieCatalog movieCatalog;

	@Autowired
	public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
		this.customerPreferenceDao = customerPreferenceDao;
	}

	// ...
}
class MovieRecommender @Autowired constructor(
	private val customerPreferenceDao: CustomerPreferenceDao) {

	@Autowired
	private lateinit var movieCatalog: MovieCatalog

	// ...
}

請確保您的目標元件(例如,MovieCatalogCustomerPreferenceDao)始終如一地透過您用於 @Autowired 註解注入點的型別宣告。否則,注入可能會因執行時發生「找不到型別匹配」錯誤而失敗。

對於透過類別路徑掃描找到的 XML 定義 Bean 或元件類別,容器通常預先知道具體型別。但是,對於 @Bean 工廠方法,您需要確保宣告的傳回型別具有足夠的表達力。對於實作多個介面的元件,或可能透過其實作型別引用的元件,請考慮在您的工廠方法上宣告最特定的傳回型別(至少與引用您的 Bean 的注入點所需的一樣特定)。

自我注入

@Autowired 也會考慮用於注入的自我參考(即,回指到目前注入的 Bean 的參考)。

但是請注意,自我注入是一種回退機制。對其他元件的常規相依性始終具有優先權。從這個意義上說,自我參考不參與常規自動裝配候選者選擇,因此尤其永遠不是主要的。相反地,它們總是最終成為最低優先權。

實際上,您應該僅將自我參考作為最後手段使用 – 例如,用於透過 Bean 的交易 Proxy 呼叫同一個實例上的其他方法。作為替代方案,請考慮在這種情況下將受影響的方法分解為單獨的委派 Bean。

另一種替代方法是使用 @Resource,它可以透過其唯一名稱取得回指到目前 Bean 的 Proxy。

嘗試在同一個 @Configuration 類別中注入 @Bean 方法的結果也實際上是一種自我參考情境。在實際需要的位置(而不是組態類別中的自動裝配欄位),延遲解析方法簽章中的此類參考,或將受影響的 @Bean 方法宣告為 static,將它們與包含組態類別實例及其生命週期解耦。否則,此類 Bean 僅在回退階段中考慮,而其他組態類別上的匹配 Bean 反而會被選為主要候選者(如果可用)。

您也可以指示 Spring 從 ApplicationContext 提供特定型別的所有 Bean,方法是將 @Autowired 註解新增到預期該型別陣列的欄位或方法,如下列範例所示

  • Java

  • Kotlin

public class MovieRecommender {

	@Autowired
	private MovieCatalog[] movieCatalogs;

	// ...
}
class MovieRecommender {

	@Autowired
	private lateinit var movieCatalogs: Array<MovieCatalog>

	// ...
}

這同樣適用於型別集合,如下列範例所示

  • Java

  • Kotlin

public class MovieRecommender {

	private Set<MovieCatalog> movieCatalogs;

	@Autowired
	public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
		this.movieCatalogs = movieCatalogs;
	}

	// ...
}
class MovieRecommender {

	@Autowired
	lateinit var movieCatalogs: Set<MovieCatalog>

	// ...
}

如果希望陣列或列表中的項目以特定順序排序,您的目標 Bean 可以實作 org.springframework.core.Ordered 介面或使用 @Order 或標準 @Priority 註解。否則,它們的順序會遵循容器中相應目標 Bean 定義的註冊順序。

您可以在目標類別層級和 @Bean 方法上宣告 @Order 註解,可能針對個別 Bean 定義(在使用相同 Bean 類別的多個定義的情況下)。@Order 值可能會影響注入點的優先順序,但請注意,它們不會影響單例啟動順序,這是一個正交問題,由相依性關係和 @DependsOn 宣告決定。

請注意,組態類別上的 @Order 註解僅影響啟動時整體組態類別集內的評估順序。此類組態層級順序值完全不會影響包含的 @Bean 方法。對於 Bean 層級排序,每個 @Bean 方法都需要有自己的 @Order 註解,該註解適用於特定 Bean 型別的多個匹配項集內(由工廠方法傳回)。

請注意,標準 jakarta.annotation.Priority 註解在 @Bean 層級不可用,因為它無法在方法上宣告。其語意可以透過 @Order 值與每個型別的單一 Bean 上的 @Primary 組合來建模。

即使是型別化的 Map 實例也可以自動裝配,只要預期的金鑰型別是 String 即可。Map 值包含預期型別的所有 Bean,而金鑰包含相應的 Bean 名稱,如下列範例所示

  • Java

  • Kotlin

public class MovieRecommender {

	private Map<String, MovieCatalog> movieCatalogs;

	@Autowired
	public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
		this.movieCatalogs = movieCatalogs;
	}

	// ...
}
class MovieRecommender {

	@Autowired
	lateinit var movieCatalogs: Map<String, MovieCatalog>

	// ...
}

預設情況下,當給定的注入點沒有可用的匹配候選 Bean 時,自動裝配會失敗。在宣告的陣列、集合或 Map 的情況下,至少需要一個匹配元素。

預設行為是將註解方法和欄位視為指示必要的相依性。您可以變更此行為,如下列範例所示,透過將無法滿足的注入點標記為非必要(即,透過將 @Autowired 中的 required 屬性設定為 false)來啟用框架跳過它

  • Java

  • Kotlin

public class SimpleMovieLister {

	private MovieFinder movieFinder;

	@Autowired(required = false)
	public void setMovieFinder(MovieFinder movieFinder) {
		this.movieFinder = movieFinder;
	}

	// ...
}
class SimpleMovieLister {

	@Autowired(required = false)
	var movieFinder: MovieFinder? = null

	// ...
}

如果非必要方法的相依性(或其相依性之一,在多個引數的情況下)不可用,則根本不會呼叫該方法。在這種情況下,非必要欄位根本不會被填入,而是保留其預設值。

換句話說,將 required 屬性設定為 false 表示對自動裝配而言,對應的屬性是選用的,如果無法自動裝配,則會忽略該屬性。這允許為屬性指派預設值,這些預設值可以選擇性地透過相依性注入覆寫。

注入的建構子和工廠方法引數是一種特殊情況,因為 @Autowired 中的 required 屬性具有稍微不同的含義,這是因為 Spring 的建構子解析演算法可能會處理多個建構子。預設情況下,建構子和工廠方法引數實際上是必要的,但在單一建構子情境中,有一些特殊規則,例如,如果沒有可用的匹配 Bean,則多元素注入點(陣列、集合、Map)會解析為空實例。這允許一種常見的實作模式,其中所有相依性都可以在唯一的多引數建構子中宣告 – 例如,宣告為沒有 @Autowired 註解的單一公用建構子。

任何給定 Bean 類別的建構子中,只能有一個建構子可以宣告 @Autowired,且 required 屬性設定為 true,表示當用作 Spring Bean 時,自動裝配的建構子。因此,如果 required 屬性保留其預設值 true,則只能使用 @Autowired 註解單一建構子。如果多個建構子宣告了註解,則它們都必須宣告 required=false,才能被視為自動裝配的候選者(類似於 XML 中的 autowire=constructor)。將選擇 Spring 容器中可以透過匹配 Bean 滿足的最大相依性數量的建構子。如果沒有候選者可以滿足,則將使用主要/預設建構子(如果存在)。同樣地,如果類別宣告了多個建構子,但它們都沒有使用 @Autowired 註解,則將使用主要/預設建構子(如果存在)。如果類別一開始只宣告單一建構子,則無論是否使用註解,都將始終使用它。請注意,註解的建構子不一定是公用的。

或者,您可以透過 Java 8 的 java.util.Optional 來表示特定相依性的非必要性質,如下列範例所示

public class SimpleMovieLister {

	@Autowired
	public void setMovieFinder(Optional<MovieFinder> movieFinder) {
		...
	}
}

您也可以使用 @Nullable 註解(任何套件中的任何種類 – 例如,JSR-305 中的 javax.annotation.Nullable),或僅利用 Kotlin 內建的空值安全支援

  • Java

  • Kotlin

public class SimpleMovieLister {

	@Autowired
	public void setMovieFinder(@Nullable MovieFinder movieFinder) {
		...
	}
}
class SimpleMovieLister {

	@Autowired
	var movieFinder: MovieFinder? = null

	// ...
}

您也可以將 @Autowired 用於眾所周知的可解析相依性介面:BeanFactoryApplicationContextEnvironmentResourceLoaderApplicationEventPublisherMessageSource。這些介面及其擴充介面(例如 ConfigurableApplicationContextResourcePatternResolver)會自動解析,無需任何特殊設定。下列範例自動裝配 ApplicationContext 物件

  • Java

  • Kotlin

public class MovieRecommender {

	@Autowired
	private ApplicationContext context;

	public MovieRecommender() {
	}

	// ...
}
class MovieRecommender {

	@Autowired
	lateinit var context: ApplicationContext

	// ...
}

@Autowired@Inject@Value@Resource 註解由 Spring BeanPostProcessor 實作處理。這表示您無法在您自己的 BeanPostProcessorBeanFactoryPostProcessor 型別(如果有的話)中應用這些註解。這些型別必須透過使用 XML 或 Spring @Bean 方法來明確「連接」。