1. 程式人生 > >spring學習總結——高級裝配學習一(處理自動裝配的歧義性)

spring學習總結——高級裝配學習一(處理自動裝配的歧義性)

自定義 soft 解決 無法 ice 與此同時 component 這樣的 異常

  我們已經看到如何使用自動裝配讓Spring完全負責將bean引用註入到構造參數和屬性中。自動裝配能夠提供很大的幫助。不過,spring容器中僅有一個bean匹配所需的結果時,自動裝配才是有效的。如果不僅有一個bean能夠匹配結果的話,Spring此時別無他法,只好宣告失敗並拋出異常。更精確地講,Spring會拋出NoUniqueBeanDefinitionException。

  當確實發生歧義性時,Spring提供了多種可選方案來解決這樣的問題。你可以將可選bean中的某一個設為首選(primary)的bean,或者使用限定符(qualifier)來幫助Spring將可選的bean的範圍縮小到只有一個bean。

例子:

需要註入的bean:

  技術分享圖片

在本例中,Dessert是一個接口,並且有三個類實現了這個接口,分別為Cake、Cookies和IceCream:

   技術分享圖片

這三個實現均使用了@Component註解,在組件掃描的時候,能夠發現它們並將其創建為Spring應用上下文裏面的bean。然後,當Spring試圖自動裝配setDessert()中的Dessert參數時,它並沒有唯一、無歧義的可選值。

Spring提供了多種可選方案來解決這樣的問題。你可以將可選bean中的某一個設為首選(primary)的bean,或者使用限定符(qualifier)來幫助Spring將可選的bean的範圍縮小到只有一個bean。

一、標示首選的bean(@Primary)

1、隱式(@Component)

  技術分享圖片

2、顯式(@Bean)

  技術分享圖片

3、xml模式:

  技術分享圖片

  在聲明bean的時候,通過將其中一個可選的bean設置為首選(primary)bean能夠避免自動裝配時的歧義性。當遇到歧義性的時候,Spring將會使用首選的bean,而不是其他可選的bean。實際上,你所聲明就是“最喜歡”的bean。

二、@Qualifier限定符

  如果有兩個繼承相同接口的類同時設置primary,則仍然會有歧義,因此引入Qualifier。Qualifier註解是使用限定符的主要方式,它可以與@AutoWired和@Inject協同使用,在註入的時候指定想要註入進去的是哪個bean。

1、基於默認的bean ID作為限定符

例如,我們想要確保要將IceCream註入到setDessert()之中:

   技術分享圖片

  為@Qualifier註解所設置的參數就是想要註入的bean的ID。所有使用@Component註解聲明的類都會創建為bean,並且bean的ID為首字母變為小寫的類名,並且如果沒有指定其他的限定符的話,所有的bean都會給定一個默認的限定符,這個限定符與bean的ID相同。因此,@Qualifier("iceCream")指向的是組件掃描時所創建的bean,並且這個bean是IceCream類的實例。

  基於默認的bean ID作為限定符是非常簡單的,但這有可能會引入一些問題。如果你重構了IceCream類,將其重命名為Gelato的話,那此時會發生什麽情況呢?如果這樣的話,bean的ID和默認的限定符會變為gelato,這就無法匹配setDessert()方法中的限定符。自動裝配會失敗。

2、創建自定義的限定符

為bean設置自己的限定符,而不是依賴於將bean ID作為限定符。在bean聲明上添加@Qualifier註解。

   技術分享圖片

在這種情況下,cold限定符分配給了IceCreambean。因為它沒有耦合類名,因此你可以隨意重構IceCream的類名,而不必擔心會破壞自動裝配。在註入的地方,只要引用cold限定符就可以了:

  技術分享圖片

在顯式模式中:

  技術分享圖片

3、使用自定義的限定符註解

錯誤示範:多個bean都具備相同特性的話,這種做法也會出現問題。可能想到的解決方案就是在註入點和bean定義的地方同時再添加另外一個@Qualifier註解

  技術分享圖片

——————————————————————————

  技術分享圖片

可是,如果有另外一個bean也同樣使用了cold限定符呢,還是會出現歧義,而java不允許同一個條目上重復出現相同類型的多個註解,否則編譯器會報錯,所以我們需要創建自定義的限定符註解,借助這樣的註解來表達bean所希望限定的特性。

當你不想用@Qualifier註解的時候,可以類似地創建@Soft、@Crispy和@Fruity。通過在定義時添加@Qualifier註解,它們就具有了@Qualifier註解的特性。它們本身實際上就成為了限定符註解。

@Qualifier("cold")被代替:

  技術分享圖片

@Qualifier("creamy")被代替:

  技術分享圖片

使用例子:

註解聲明bean:

IceCream類可以添加@Cold和@Creamy註解:

  技術分享圖片

Popsicle類可以添加@Cold和@Fruity註解:

  技術分享圖片

註入bean:

   技術分享圖片

通過聲明自定義的限定符註解,我們可以同時使用多個限定符,不會再有Java編譯器的限制或錯誤。與此同時,相對於使用原始的@Qualifier並借助String類型來指定限定符,自定義的註解也更為類型安全。

spring學習總結——高級裝配學習一(處理自動裝配的歧義性)