上面梳理了經過註解來隱式的完成了組件的掃描和自動裝配,下面來學習下如何經過顯式的配置的裝配beanjava
在前面定義了HelloWorldConfig類,並使用@ComponentScan和@Configuration註解,@Configuration註解代表了這個類是一個java配置類,該類用在獲取Spring應用上下文時,告訴Spring建立bean的細節,經過@ComponentScan,咱們啓用了Spring的自動組件掃描,如今就讓咱們來看若是經過java類來顯式的配置bean,下面咱們經過一個音樂播放器的案例來實踐一下。spring
咱們播放音樂,首先須要一個播放器,而後須要音樂資源,首先咱們定義一個播放器接口和音樂資源接口ide
package com.seven.springTest.service; // 播放器 public interface MediaPlayer { void play(); }
package com.seven.springTest.service; // 音樂資源 public interface MusicSource { void play(); }
本次播放音樂咱們是光驅來播放cd音樂,下面咱們來實現上面的接口,函數
package com.seven.springTest.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.seven.springTest.service.MusicSource; import com.seven.springTest.service.MediaPlayer; //定義光驅播放器 public class CDPlayer implements MediaPlayer { @Autowired // 定義一個音樂資源,這裏經過@Autowired來聲明須要注入MusicSource的依賴 private MusicSource cd ; @Override public void play() { //播放音樂 cd.play(); } }
實現音樂資源爲光盤學習
package com.seven.springTest.service.impl; import com.seven.springTest.service.MusicSource; public class CDSource implements MusicSource { private String title = "七里香"; private String artist = "周杰倫"; @Override public void play() { System.out.println("Playing " + title + " by " + artist); } }
到目前爲止咱們已經完成播放器、音樂資源的接口定義和具體的實現,那麼咱們若是告訴Spring應該建立哪麼bean,併爲它們注入什麼依賴呢?在第一部分,咱們經過@Component註解來隱式的告訴Spring,如今咱們經過java類來配置bean組件。測試
@Bean註解告訴Spring函數將返回一個對象,該對象須要註冊爲Spring應用上下文中的bean,該方法中包含了產生bean實例的邏輯code
package com.seven.springTest.Configuration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import com.seven.springTest.service.MusicSource; import com.seven.springTest.service.MediaPlayer; import com.seven.springTest.service.impl.CDPlayer; import com.seven.springTest.service.impl.CDSource; @Configuration public class MediePlayerConfig { @Bean //該方法返回的MusicSource對象須要註冊爲Spring應用上下文中的bean public MusicSource cdsource(){ return new CDSource(); } @Bean //該方法返回的MediaPlayer對象須要註冊爲Spring應用上下文中的bean public MediaPlayer cdplayer(){ return new CDPlayer(); } }
MediePlayerConfig類中,咱們只添加了@Configuration註解,以前的@ComponentScan註解移除了,沒有配置啓動Spring的組件掃描,另外接口的實現類也沒有添加@Component註解,咱們經過@Bean註解來告訴Spring哪些對象須要被註冊爲Spring應用上下文中的bean。cdsource()方法返回了一個MusicSource類型的實例對象CDSource,該對象被註冊到Spring應用上下文,一樣的cdplayer()方法返回了一個MediaPlayer類型的實例CDPlayer註冊到Spring應用上下文中。下面咱們來測試下xml
package com.seven.springTest.main; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.seven.springTest.Configuration.MediePlayerConfig; import com.seven.springTest.Configuration.HelloWorldConfig; import com.seven.springTest.service.MediaPlayer; public class MediaPlayerTest { public static void main(String[] args) { //加載java配置類獲取Spring應用上下文 ApplicationContext ac = new AnnotationConfigApplicationContext(MediePlayerConfig.class); //獲取播放器 MediaPlayer player= ac.getBean(MediaPlayer.class); //播放 player.play(); } }
咱們在獲取播放器bean的時候,其實獲取到的就是MediePlayerConfig類中cdplayer()返回的對象CDPlayer,在CDPlayer中咱們依賴MusicSource,經過@Autowired註解,Spring自動爲該bean注入了對MusicSource的依賴,因此在測試代碼中咱們只是獲取了MediaPlayer對象的實例player,至於player有哪些依賴,咱們都不知道,都是由Spring容器來給我注入,這裏只關心播放器player,這就是Spring給咱們帶來的便捷,咱們不須要用代碼去管理對象的依賴關係,對象全部依賴的資源都有Spring容器來爲咱們注入。對象
隨着技術的發展,有一天光驅也能夠插入U盤播放MP3音樂了,這個時候咱們來實現一個MP3的音樂資源接口
package com.seven.springTest.service.impl; import com.seven.springTest.service.MusicSource; public class MP3Source implements MusicSource { private String title = "外婆"; private String artist = "周杰倫"; @Override public void play() { // TODO Auto-generated method stub System.out.println("MP3 Playing " + title + " by " + artist); } }
在第一部分自動裝配中,若是Spring發現了多個bean知足依賴關係,Spring就沒法選擇了,那麼若是咱們定義了MP3Source的實現,如今會不會也出現這樣的狀況呢?經過運行程序,咱們發現沒有產生任何影響,CDPlayer bean被注入的MusicSource依賴仍是CDSource。這是由於咱們在MediePlayerConfig中經過cdsource()告知了Spring產生bean的實現邏輯,那咱們來修改下cdsource()
@Bean //該方法返回的MusicSource對象須要註冊爲Spring應用上下文中的bean public MusicSource cdsource(){ //返回MP3Source實例 return new MP3Source(); }
咱們再運行下測試方法,發現輸出內容變成了「==MP3 Playing 外婆 by 周杰倫==」,說明注入的依賴對象實現發生變化了,這是由於 cdsource()內實現的是返回MP3Source的實例。
同以前@Component同樣,添加@Bean註解的方法返回的bean也會被默認分配一個ID,默認狀況下和方法名相同,如cdsource()方法返回的bean的ID就爲「cdsource」,咱們也能夠指定bean的ID,以下:
@Bean(name="myCdplayer") //該方法返回的MediaPlayer對象須要註冊爲Spring應用上下文中的bean public MediaPlayer cdplayer(){ return new CDPlayer(); }
這樣在獲取bean的時候就能夠經過ID來獲取
public class MediaPlayerTest { public static void main(String[] args) { //加載java配置類獲取Spring應用上下文 ApplicationContext ac = new AnnotationConfigApplicationContext(MediePlayerConfig.class); //根據ID獲取bean MediaPlayer player= (MediaPlayer) ac.getBean("myCdplayer"); //播放 player.play(); } }
上面的案例中CDPlayer bean它依賴了MusicSource的依賴,咱們在CDPlayer類中經過@Autowired聲明瞭CDPlayer須要的依賴,這裏仍是一種經過註解隱式的配置,下面咱們來經過java配置類來實現。
若是是顯式的配置,因爲MediePlayerConfig中配置的bean都是經過方法返回的,因此須要在返回對象bean的方法裏注入依賴:
@Bean(name="myCdplayer") //該方法返回的MediaPlayer對象須要註冊爲Spring應用上下文中的bean public MediaPlayer cdplayer(){ return new CDPlayer(cdsource()); //經過對象的構造函數注入依賴 }
或者
@Bean(name="myCdplayer") //該方法返回的MediaPlayer對象須要註冊爲Spring應用上下文中的bean public MediaPlayer cdplayer(MusicSource musicSource){ return new CDPlayer(musicSource); //經過對象的構造函數注入依賴 }
經過上面2中方式配置,Spring均可以對CDPlayer中的MusicSource對象完成依賴注入,下面咱們在定義一個bean配置
@Bean(name="myCdplayer") //該方法返回的MediaPlayer對象須要註冊爲Spring應用上下文中的bean public MediaPlayer cdplayer(){ return new CDPlayer(cdsource()); //經過對象的構造函數注入依賴 } @Bean(name="otherCdplayer") //定義另一個bean對象, public MediaPlayer othercdplayer(){ return new CDPlayer(cdsource()); }
MediaPlayer接口增長一個獲取播放資源的方法
package com.seven.springTest.service; public interface MediaPlayer { /** * 獲取播放器加載的資源 * @return MusicSource */ MusicSource getResource(); /** * 播放 */ void play(); }
解下列,咱們修改下Test代碼
package com.seven.springTest.main; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.seven.springTest.Configuration.MediePlayerConfig; import com.seven.springTest.Configuration.HelloWorldConfig; import com.seven.springTest.service.MediaPlayer; public class MediaPlayerTest { public static void main(String[] args) { // 加載java配置類獲取Spring應用上下文 ApplicationContext ac = new AnnotationConfigApplicationContext(MediePlayerConfig.class); // 獲取播放器 MediaPlayer player = (MediaPlayer) ac.getBean("myCdplayer"); MediaPlayer otherplayer = (MediaPlayer) ac.getBean("otherCdplayer"); if (player.getResource().equals(otherplayer.getResource())) { System.out.println("true"); } // 播放 //player.play(); } }
運行後,咱們發現輸出「true」,這說明的什麼狀況呢,咱們在cdplayer()和othercdplayer()方法中在調用CDPlayer(cdsource())構造時,經過cdsource()獲取的音樂資源對象是相同的,在默認狀況下,Spring中的bean都是單例的,Spring會攔截對cdsource()的調用,並確保返回的是Spring建立的bean,也就是Spring自己在第一次調用cdsource()所建立的bean。