使用 @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)

如果目標 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

	// ...

}

你可以將 @Autowired 應用於具有任意名稱和多個引數的方法,如以下示例所示

  • 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 定義的註冊順序。

你可以將 @Order 註解宣告在目標類級別和 @Bean 方法上,可能用於單個 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 可用時,自動裝配會失敗。在宣告的陣列、集合或對映的情況下,期望至少有一個匹配元素。

預設行為是將註解方法和欄位視為指示必需依賴項。你可以更改此行為,如以下示例所示,透過將其標記為非必需(即,透過將 @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 可用時解析為空例項。這允許一種常見的實現模式,其中所有依賴項都可以在唯一的多個引數建構函式中宣告——例如,宣告為沒有 @Autowired 註解的單個公共建構函式。

任何給定 bean 類中只能有一個建構函式宣告 @Autowired 並將 required 屬性設定為 true,這表示當用作 Spring bean 時要自動裝配的那個建構函式。因此,如果 required 屬性保留其預設值 true,則只能有一個建構函式可以註解 @Autowired。如果多個建構函式聲明瞭該註解,則它們都必須宣告 required=false 才能被視為自動裝配的候選者(類似於 XML 中的 autowire=constructor)。將選擇 Spring 容器中可以滿足最多依賴項的建構函式。如果所有候選者都無法滿足,則將使用主/預設建構函式(如果存在)。類似地,如果一個類聲明瞭多個建構函式但沒有一個用 @Autowired 註解,則將使用主/預設建構函式(如果存在)。如果一個類一開始只宣告一個建構函式,則即使未註解,它也始終會被使用。請注意,註解的建構函式不必是公共的。

或者,你可以透過 Java 的 java.util.Optional 表達特定依賴項的非必需性質,如以下示例所示

public class SimpleMovieLister {

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

你還可以使用引數級別的 @Nullable 註解(任何包中的任何型別——例如,JSpecify 中的 org.jspecify.annotations.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 方法明確地“連線”起來。

© . This site is unofficial and not affiliated with VMware.