spring學習總結——高級裝配學習一(處理自動裝配的歧義性)
我們已經看到如何使用自動裝配讓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學習總結——高級裝配學習一(處理自動裝配的歧義性)