使用 @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 的事務代理呼叫同一例項上的其他方法。作為替代方案,在這種情況下,考慮將受影響的方法重構到一個單獨的委託 bean 中。

另一種替代方案是使用 @Resource,它可以透過其唯一名稱獲取當前 bean 的代理。

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

您還可以透過將 @Autowired 註解新增到需要該型別陣列的欄位或方法中,指示 Spring 從 ApplicationContext 提供該特定型別的所有 bean,如下例所示

  • 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。對映的值包含所有期望型別的 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 表示對應的屬性對於自動裝配目的來說是可選的,並且如果無法自動裝配,則該屬性將被忽略。這允許為屬性分配可以透過依賴注入可選地覆蓋的預設值。

注入的建構函式和工廠方法引數是一種特殊情況,因為 Spring 的建構函式解析演算法可能處理多個建構函式,導致 @Autowired 中的 required 屬性具有一些不同的含義。建構函式和工廠方法引數預設實際上是必需的,但在單個建構函式場景中有一些特殊規則,例如多元素注入點(陣列、集合、map)在沒有匹配 bean 可用時解析為空例項。這允許一種常見的實現模式,其中所有依賴項都可以在唯一的多個引數建構函式中宣告——例如,宣告為一個沒有 @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

	// ...
}

Spring Framework 6.2 尚不支援 JSpecify 等型別級別的 @Nullable 註解。您需要升級到 Spring Framework 7.0,在該版本中,框架可以檢測型別級別的註解,並在其自身程式碼庫中一致地宣告 JSpecify。

您還可以對眾所周知的可解析依賴介面使用 @AutowiredBeanFactoryApplicationContextEnvironmentResourceLoaderApplicationEventPublisherMessageSource。這些介面及其擴充套件介面(例如 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 方法顯式地“連線”起來。