不知大家可曾想過這樣一些問題:“在基於XML或基於Java的顯示配置中,假如需要配置的Bean很多,這時把所有Bean的配置信息全都填在一個配置文件里,難道不會導致配置文件非常臃腫,非常難以維護嗎?還有,假如因為某些原因不得不把一些Bean的配置信息填在XML配置文件里,把一些Bean的配置信息填在 ...
不知大家可曾想過這樣一些問題:“在基於XML或基於Java的顯示配置中,假如需要配置的Bean很多,這時把所有Bean的配置信息全都填在一個配置文件里,難道不會導致配置文件非常臃腫,非常難以維護嗎?還有,假如因為某些原因不得不把一些Bean的配置信息填在XML配置文件里,把一些Bean的配置信息填在Java配置類里,而XML配置文件里的Bean與Java配置類里的Bean是有依賴關係的,這時又該怎麼配置?”
面對這樣一些問題,混合配置是個好的解決方案。因為混合配置能把多個XML配置文件,多個Java配置類串聯起來,使之作為一個整體能被Spring容器載入之後進行Bean的創建與裝配。具體來說,混合配置支持這樣一些配置方式:
1.在Java配置類里添加@Import註解,導入其它Java配置類。
2.在Java配置類里添加@ImportResource註解,導入XML配置文件。
3.在XML配置文件里添加<import>元素,導入其它XML配置文件。
4.在XML配置文件里添加<bean>元素,導入Java配置類。
至於這些配置方式具體是怎樣的,且讓我們分成四個小節仔細談談。
@Import註解與Java配置類的導入
顧名思義,@Import註解就是用來導入某些東西的;而這東西,就是Java配置類。比如,我們可把Music類的創建信息放在MusicConfig配置類里:
1 @Configuration 2 public class MusicConfig { 3 @Bean("music") 4 public Music produceMusic() { 5 return new Music("Dream"); 6 } 7 }
把Player類的創建信息放在PlayerConfig配置類里:
1 @Configuration 2 public class PlayerConfig { 3 @Bean("player") 4 public Player producePlayer(Music playingMusic) { 5 return new Player(playingMusic); 6 } 7 }
之後通過@Import註解把這兩個配置類導入AppConfig配置類中:
1 @Configuration 2 @Import(value = { MusicConfig.class, PlayerConfig.class }) 3 public class AppConfig { 4 }
@Import註解有個Class<?>[]類型的value屬性,能向它指定一個Class<?>類型的數組,導入多個Java配置類。因此,AppConfig配置類通過 @Import(value = { MusicConfig.class, PlayerConfig.class }) 註解導入MusicConfig,PlayerConfig兩個配置類。之後,我們只要把AppConfig配置類交給Spring容器,Spring容器就能創建Bean了。如下所示:
1 try (var context = new AnnotationConfigApplicationContext(AppConfig.class)) { 2 var player = context.getBean("player", Player.class); 3 // 省略其它代碼... 4 }
這段代碼把AppConfig配置類交給AnnotationConfigApplicationContext類型的Spring容器。Spring容器瞧見配置類上的@Import註解之後,就會導入@Import註解指定的MusicConfig和PlayerConfig配置類。這意味著Spring容器不僅會載入AppConfig配置類,還會載入導入的MusicConfig和PlayerConfig配置類;根據AppConfig,MusicConfig,PlayerConfig三個配置類提供的配置信息開始Bean的創建。
還有,Player類型的Bean是依賴於Music類型的Bean的。因此,配置方法 public Player producePlayer(Music playingMusic) 帶有一個Music類型的參數。Spring容器調用這個方法創建Bean的時候,知道配置方法帶有一個Music類型的參數,於是自動從Spring容器里找到Music類型的Bean裝配上去。當然,我們也可往配置方法添加@Autowired註解,告訴Spring容器進行Bean的自動裝配;可往配置方法添加@Primary註解或@Qualifier註解,告訴Spring容器如何解決自動裝配的歧義性。由此可見,不同配置類之間的Bean是能通過自動裝配完成組裝的。當然,配置類分為兩種:一種是顯式配置;一種是自動配置。@Import註解導入自動配置的配置類和導入顯式配置的配置類是一樣的,不再贅敘。
@ImportResource註解與XML配置文件的導入
Java配置類除了能用@Import註解導入其它配置類之外,也能使用@ImportResource註解導入XML配置文件。也就是說,Spring是支持Java配置類與XML配置文件的混合配置的。比如,我們可把Player類的配置信息放在player-config.xml里:
1 <beans /* 省略命名空間和XSD模式文件聲明 */> 2 <bean id="player" class="com.dream.Player"> 3 <constructor-arg type="com.dream.Music" ref="music" /> 4 </bean> 5 </beans>
把Music類的配置信息放在MusicConfig配置類里:
1 @ComponentScan 2 public class MusicConfig { 3 @Bean("music") 4 public Music produceMusic() { 5 return new Music("Dream"); 6 } 7 }
之後通過@ImportResource註解把player-config.xml和MusicConfig配置類混合導入AppConfig配置類里:
1 @Configuration 2 @Import(value = MusicConfig.class) 3 @ImportResource(value = {"classpath:com//dream//player-config.xml"}) 4 public class AppConfig { 5 }
<import>元素與XML配置文件的導入
和Java配置類能導入其它Java配置類一樣,XML配置文件也能導入其它XML配置文件。比如,我們可把Music類的配置信息放在music-config.xml里:
1 <beans /* 省略命名空間和XSD模式文件聲明 */> 2 <bean id="music" class="com.dream.Music"> 3 <constructor-arg type="java.lang.String" value="Dream" /> 4 </bean> 5 </beans>
把Player類的配置信息放在player-config.xml里:
1 <beans /* 省略命名空間和XSD模式文件聲明 */> 2 <bean id="player" class="com.dream.Player"> 3 <constructor-arg type="com.dream.Music" ref="music" /> 4 </bean> 5 </beans>
之後可在app-config.xml里這樣導入XML配置文件:
1 <beans /* 省略命名空間和XSD模式文件聲明 */> 2 <import resource="classpath:com/dream/music-config.xml" /> 3 <import resource="classpath:com/dream/player-config.xml" /> 4 </beans>
XML配置文件是由<import>元素導入的。<import>元素有個resource屬性,用於指定即將導入的XML配置文件的路徑。這裡,app-config.xml配置文件通過<import>元素導入了music-config.xml和player-config.xml兩個配置文件。
<bean>元素與Java配置類的導入
往XML配置文件里導入Java配置類有點特別,需要做好兩件事情:
1.啟用基於註解的配置,告訴Spring容器需要解析諸如@Configuration之類的註解。
2.往XML配置文件里添加Java配置類的Bean,以使Spring容器能夠載入Java配置類,導入Java配置類。
比如,我們可把Player類的配置信息放在PlayerConfig配置類里:
1 @Configuration 2 public class PlayerConfig { 3 @Bean("player") 4 public Player producePlayer(Music playingMusic) { 5 return new Player(playingMusic); 6 } 7 }
把Music類的配置信息放在music-config.xml配置文件里:
1 <beans /* 省略命名空間和XSD模式文件聲明 */> 2 <bean id="music" class="com.dream.Music"> 3 <constructor-arg type="java.lang.String" value="Dream" /> 4 </bean> 5 </beans>
之後可在app-config.xml配置文件里這樣混合導入Java配置類和XML配置文件:
1 <beans /* 省略命名空間和XSD模式文件聲明 */> 2 <context:annotation-config /> 3 4 <bean class="com.dream.PlayerConfig" /> 5 <import resource="classpath:com/dream/music-config.xml" /> 6 </beans>
為了導入Java配置類,我們首先引入<context:annotation-config />元素啟用基於註解的配置。之後使用<bean class="com.dream.PlayerConfig" />元素創建PlayerConfig類型的Bean。Spring容器創建PlayerConfig類型的Bean時,知道類上帶有@Configuration註解,是個配置類;於是載入該配置類進行Bean的創建,從而完成PlayerConfig配置類的導入。
至此,關於混合配置的介紹也就告一段落了。下章,我們將會開始介紹Profile。歡迎大家繼續閱讀,謝謝大家!