@Autowired注解能讓Spring容器找到型別匹配的Bean之后自動進行裝配,同時,這也引出這樣一個問題:“假如Spring容器存在多個型別相同的Bean,Spring容器怎么知道應該自動裝配哪個Bean呢?”舉個例子,假如com.dream包現有這樣一些類:
1 public interface Music { 2 }
1 @Component 2 public class PopMusic implements Music { 3 }
1 @Component 2 public class ClassicMusic implements Music { 3 }
1 @Component 2 public class CountryMusic implements Music { 3 }
1 @Component 2 public class Player { 3 private Music music = null; 4 5 @Autowired 6 public Player(Music music) { 7 this.music = music; 8 } 9 }
這些代碼定義了一個Music介面;三個實作了Music介面的PopMusic類,ClassicMusic類,CountryMusic類;一個Player類,其中,PopMusic類,ClassicMusic類,CountryMusic類,Player類是組件,能被組件掃描發現之后進行創建,另外,Player建構式帶有@Autowired注解,能夠自動裝配Music型別的Bean,可是,當我們覺得萬事具備,開始運行時卻發現程式拋出NoUniqueBeanDefinitionException型別的例外,根本無法完成Bean的創建與裝配,
這是怎么回事呢?
原來,Spring容器創建Player時,發現Spring容器存在PopMusic,ClassicMusic,CountryMusic三個Music型別的Bean,一時之間不知如何選擇,于是拋出NoUniqueBeanDefinitionException型別的例外,
那該怎么辦呢?
一種解決方法是引入@Primary注解,把某個Bean標為首選,這樣,當型別相同的Bean多于一個時,Spring容器就知道應該選用首選的那個進行裝配了,因此,如果我們想讓Spring容器選用PopMusic,可把PopMusic標為首選,如下所示:
1 @Primary 2 @Component 3 public class PopMusic implements Music { 4 }
現在,PopMusic帶有@Primary注解,這樣,Spring容器裝配Player時,就知道該在PopMusic,ClassicMusic,CountryMusic三個Music型別的Bean里選用PopMusic了,
還有一種情況,假如現有兩種音樂播放器:一種是DVD播放器;一種是數字播放器,定義如下:
1 @Component 2 public class DvdPlayer { 3 private Music music = null; 4 5 @Autowired 6 public DvdPlayer(Music music) { 7 this.music = music; 8 } 9 }
1 @Component 2 public class DigitalPlayer { 3 private Music music = null; 4 5 @Autowired 6 public DigitalPlayer(Music music) { 7 this.music = music; 8 } 9 }
可以看到DvdPlayer,DigitalPlayer的建構式引數都是Music型別的,如果我們希望DvdPlayer播放的是PopMusic,DigitalPlayer播放的是ClassicMusic,這時,該怎么辦呢?
毫無疑問,@Primary注解只能標注一個首選,而且Spring容器只會選用那個標為首選的Bean進行裝配,這意味著光靠@Primary注解根本無法達成我們的目的,
那該怎么辦呢?
直覺告訴我們,Spring還提供了其它方式用于解決自動裝配存在的歧義問題,事實也確實如此,@Qualifier注解就是Spring提供的另一種方式,因此,我們可以使用@Qualifier注解這樣解決問題:
1 @Component 2 @Qualifier("popMusicQualifier") 3 public class PopMusic implements Music { 4 }
1 @Component 2 public class DvdPlayer { 3 private Music music = null; 4 5 @Autowired 6 public DvdPlayer(@Qualifier("popMusicQualifier") Music music) { 7 this.music = music; 8 } 9 }
1 @Component 2 @Qualifier("classicMusicQualifier") 3 public class ClassicMusic implements Music { 4 }
@Component public class DigitalPlayer { private Music music = null; @Autowired public DigitalPlayer(@Qualifier("classicMusicQualifier") Music music) { this.music = music; } }
可以看到@Qualifier注解能以限定符的方式指定需要注入的Bean,具體如下:
1.添加@Qualifier注解到Bean上,指定Bean的限定符為某值
2.添加@Qualifier注解到需要注入依賴的引數旁邊,指定即將注入的Bean須是限定符為某值的Bean
這樣之后,Bean與Bean的注入就通過限定符關聯起來了,自然而然的,Spring容器也就知道怎樣通過限定符找到匹配的Bean進行自動裝配了,
于是,我們在PopMusic類上添加了@Qualifier("popMusicQualifier")注解,在DvdPlayer的建構式的引數旁邊也添加了@Qualifier("popMusicQualifier")注解,從而告訴Spring容器把PopMusic注入DvdPlayer的建構式中;我們在ClassicMusic類上添加了@Qualifier("classicMusicQualifier")注解,在DigitalPlayer的建構式引數旁邊也添加了@Qualifier("classicMusicQualifier")注解,從而告訴Spring容器把ClassicMusic注入DigitalPlayer的建構式中,
還有,Bean的限定符默認是Bean的ID,我們知道添加@Component注解之后,Spring容器創建的Bean其ID默認是類名的第一個字母變成小寫之后的字串,也就是說,PopMusic這個Bean的ID是popMusic,ClassicMusic這個Bean的ID是classicMusic,因此,我們還能把@Qualifier注解從PopMusic類和ClassicMusic類上刪掉,而后指定DvdPlayer,DigitalPlayer的建構式引數旁邊的@Qualifier注解的限定符為Bean的ID,如下所示:
1 @Component 2 public class DvdPlayer { 3 private Music music = null; 4 5 @Autowired 6 public DvdPlayer(@Qualifier("popMusic") Music music) { 7 this.music = music; 8 } 9 }
1 @Component 2 public class DigitalPlayer { 3 private Music music = null; 4 5 @Autowired 6 public DigitalPlayer(@Qualifier("classicMusic") Music music) { 7 this.music = music; 8 } 9 }
于是,關于自動裝配的歧義問題,我們已經知道怎么解決了,下章該談談屬性占位符,看看怎樣把屬性檔案里的值讀取出來之后通過@Value注解注入Bean里,歡迎大家繼續閱讀,謝謝大家!
回傳目錄 下載代碼
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/423290.html
標籤:其他
