首頁 >Java >java教程 >春季 - 為什麼要逐名 - 擬議中的標準

春季 - 為什麼要逐名 - 擬議中的標準

DDD
DDD原創
2025-01-28 22:08:11209瀏覽

spring-: why-spring-cannot-match-by-name-for-injection

Spring 依賴注入:為何無法自動按名稱匹配?

Spring 的依賴注入機制主要基於類型,而非名稱。當遇到多個相同類型的 Bean 時(例如 TenantDataSource),它不會自動回退到按參數名稱匹配。這是因為 Spring 無法始終保證方法中的參數名稱與 Bean 名稱匹配。

Java 默認情況下不會在編譯後的字節碼中保留參數名稱。如果沒有特殊配置,參數名稱(例如 tenantADataSource 和 tenantBDataSource)會在編譯期間被清除,並替換為通用的名稱,如 arg0 和 arg1。 因此,Spring 無法得知 tenantADataSource 指的是名為 "tenantA-dataSource" 的 Bean。

解決參數名稱保留問題

可以使用 -parameters 編譯器標誌來保留字節碼中的參數名稱:

<code>javac -parameters MyClass.java</code>

即使使用了此標誌,Spring 仍然不會按參數名稱匹配,除非明確配置。

Spring 避免做出假設以防止意外行為。例如,如果參數名稱意外交換或命名錯誤,或者開發人員期望不同的映射,會發生什麼? 如果沒有明確的指導(例如 @Qualifier),Spring 無法確定開發人員的意圖,而選擇拋出錯誤,而不是可能注入錯誤的 Bean。

Spring 遵循“顯式優於隱式”的原則。依賴注入應該具有可預測性,並且不依賴於參數名稱到 Bean 名稱匹配之類的假設。 Spring 的運作方式在不同的環境和框架中保持一致。某些語言或框架(如 Kotlin)默認保留參數名稱,而其他語言則不保留,因此 Spring 避免依賴參數名稱來實現關鍵功能。

何時名稱匹配可以自動工作?

雖然 Spring 默認情況下不按參數名稱匹配,但在某些情況下可以按參數名稱匹配,但這取決於您的設置:

Spring 4.3 參數名稱發現

如果使用 -parameters 標誌編譯代碼,當存在歧義時,Spring 可以從參數名稱推斷 Bean 名稱。

示例:

<code>@Autowired
public TenantService(TenantDataSource tenantADataSource, TenantDataSource tenantBDataSource) {
    this.tenantADataSource = tenantADataSource;
    this.tenantBDataSource = tenantBDataSource;
}</code>

如果使用了 -parameters 標誌並且參數名稱(tenantADataSource、tenantBDataSource)與 Bean 名稱匹配,Spring 可以解決歧義。但是,這種行為在復雜的配置中並不總是可靠或可預測的,這就是為什麼首選顯式配置(例如 @Qualifier)。

為什麼 Spring 更傾向於使用 @Qualifier?

使用 @Qualifier 可以確保清晰度並消除歧義,使開發人員和框架都能明確意圖。

示例:

<code>@Autowired
public TenantService(
    @Qualifier("tenantA-dataSource") TenantDataSource tenantADataSource,
    @Qualifier("tenantB-dataSource") TenantDataSource tenantBDataSource
) {
    this.tenantADataSource = tenantADataSource;
    this.tenantBDataSource = tenantBDataSource;
}</code>

這樣,Spring 就能準確知道要注入哪些 Bean,而不管參數名稱或其他因素如何。

Spring 應該更智能嗎?

有人可能會認為像 Spring 這樣的框架應該更智能,並在存在歧義時自動將 Bean 名稱與參數名稱匹配。但是:

  1. 向後兼容性: 自動更改此行為可能會破壞 Bean 名稱和參數名稱不匹配的現有應用程序。
  2. 可預測性: 顯式地解決歧義(例如,通過 @Qualifier)確保開發人員始終知道正在註入哪些 Bean。隱式假設可能會導致難以調試的問題,尤其是在大型複雜應用程序中。

真實場景中的情況

在大多數實際應用程序中:

  • 開發人員使用有意義的 Bean 名稱和參數名稱,但他們也更喜歡像 @Qualifier 這樣的顯式配置以確保清晰度。
  • 對於多實例場景,通常使用動態配置基於工廠的方法(例如 AbstractRoutingDataSource),而不是手動連接各個 Bean。

關鍵要點

  1. Spring 首先按類型注入: 如果只有一種類型的 Bean,Spring 會毫無問題地註入它。如果存在多種相同類型的 Bean,Spring 需要額外的提示(例如 @Qualifier)來解決歧義。
  2. 參數名稱不可靠: 默認情況下,參數名稱不會保留在 Java 字節碼中,因此 Spring 無法使用它們將 Bean 與參數匹配。即使保留了參數名稱(-parameters),Spring 也會避免隱式基於名稱的匹配,除非明確配置。
  3. 顯式優於隱式: Spring 優先考慮可預測性,並鼓勵開發人員使用顯式配置(例如 @Qualifier@Primary)而不是依賴於隱式匹配。
  4. Spring 的設計理念: 歧義錯誤可以防止意外行為,並確保開發人員完全控制依賴注入。

以上是春季 - 為什麼要逐名 - 擬議中的標準的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn