通過Java代碼裝配Bean
上面梳理了通過註解來隱式的完成了組件的掃描和自動裝配,下面來學習下如何通過顯式的配置的裝配bean
二、通過Java類裝配bean
在前面定義了HelloWorldConfig類,並使用@ComponentScan和@Configuration註解,@Configuration註解表明了這個類是一個java配置類,該類用在獲取Spring應用上下文時,告訴Spring創建bean的細節,通過@ComponentScan,我們啟用了Spring的自動組件掃描,現在就讓我們來看如果通過java類來顯式的配置bean,下面我們通過一個音樂播放器的案例來實踐一下。
我們播放音樂,首先需要一個播放器,然後需要音樂資源,首先我們定義一個播放器接口和音樂資源接口
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
@Bean註解告訴Spring函數將返回一個對象,該對象需要註冊為Spring應用上下文中的bean,該方法中包含了產生bean實例的邏輯
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應用上下文中。下面我們來測試下
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。
通過Java代碼裝配Bean