Spring中隱式的bean發(fā)現(xiàn)機(jī)制和自動(dòng)裝配

盡管Spring的配置風(fēng)格是可以互相搭配的,但是應(yīng)該盡可能的使用自動(dòng)配置的機(jī)制,顯式配置越少越好

Spring從兩個(gè)角度來實(shí)現(xiàn)自動(dòng)化裝配:

  • 組件掃描:Spring會(huì)自動(dòng)發(fā)現(xiàn)應(yīng)用上下文中所創(chuàng)建的bean
  • 自動(dòng)裝配:Spring會(huì)自動(dòng)滿足bean之間的依賴

組件掃描和自動(dòng)裝配組合在一起就可以將所需要的顯式配置降低到最少。

首先定義一個(gè)代表了CD概念的接口CompactDisc:

public interface CompactDisc {
  void play();
}

作為一個(gè)接口,它將CD播放器和CD之間的耦合降低到了最小的程度。

下面創(chuàng)建一個(gè)CD接口的實(shí)現(xiàn)SgtPeppers類:

import org.springframework.stereotype.Component;
 
@Component
public class SgtPeppers implements CompactDisc {
 
  private String title = "Sgt. Pepper's Lonely Hearts Club Band";  
  private String artist = "The Beatles";
  
  public void play() {
    System.out.print("Playing " + title+" by " + artist);
  }
  
}

注意在這里使用了@Component注解,這個(gè)注解表明該類會(huì)作為組件類,并告知Spring為該類創(chuàng)建bean。只需要使用了這個(gè)注解,就沒有必要顯式配置SgtPeppers bean,Spring會(huì)把所有任務(wù)處理妥當(dāng)。

我們可以在@Component注解中為bean命名,如果采取默認(rèn)ID的話,Spring會(huì)根據(jù)類名指定一個(gè)ID,具體規(guī)則就是將類名的第一個(gè)字母變成小寫。如果需要自定義ID的話,可以采取下面這樣的方式配置注解:

import org.springframework.stereotype.Component;
 
@Component("happyBean")
public class SgtPeppers implements CompactDisc {
}

不過需要注意的是:組件掃描默認(rèn)是不啟用的。我們需要顯式配置一下Spring,從而命令它去尋找所有帶有@Component注解的類,并為它創(chuàng)建bean。

下面這個(gè)CDPlayerConfig類展現(xiàn)了如何實(shí)現(xiàn)顯式配置Spring的組件掃描:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
 
@Configuration
@ComponentScan
public class CDPlayerConfig { 
}

在CDPlayerConfig類中沒有顯式聲明任何bean,但是它通過使用@ComponentScan注解,讓Spring啟用了組件掃描。如果沒有其他配置的話,Spring會(huì)默認(rèn)掃描與配置類相同的包。

如果希望Spring不僅僅掃描默認(rèn)的基礎(chǔ)包,那么我們可以采用如下的方式進(jìn)行配置:

@Configuration
@ComponentScan(basePackages = {"soundsystem","video"})
public class CDPlayerConfig { 
}

但是采用這樣的方法是類型不安全的,如果需要重構(gòu)代碼的話,那么所指定的基礎(chǔ)包就可能出現(xiàn)錯(cuò)誤。除了將包設(shè)置為簡單的String之外,@Component還提供了另一種方法,那就是將其指定為包中所包含的類或者接口:

@Configuration
@ComponentScan(basePackageClasses = {CDPlayer.class, Video.class})
public class CDPlayerConfig { 
}

雖然在上面的示例中使用的是組件類,但是我們應(yīng)該考慮在包中創(chuàng)建一個(gè)用來進(jìn)行掃描的空標(biāo)記接口。通過標(biāo)記接口的方式,依然能夠保持對重構(gòu)友好的接口引用,同時(shí)能夠避免引用任何實(shí)際的應(yīng)用程序代碼。

下面我們使用測試類來測試CompactDisc是不是真的創(chuàng)建出來了:

import static org.junit.Assert.*;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=CDPlayerConfig.class)
public class CDPlayerTest {
  
  @Autowired
  private CompactDisc cd;
  
  @Test
  public void cdShouldNotBeNull() {
    assertNotNull(cd);
  }
}

這個(gè)測試類自動(dòng)創(chuàng)建了Spring應(yīng)用上下文,注解@ContextConfiguration告訴其需要在CDPlayerConfig中加載配置。因?yàn)镃DPlayerConfig類中包含了@ComponentScan,因此最終的應(yīng)用上下文應(yīng)該包含了CompactDisc bean。

這個(gè)測試類應(yīng)該可以通過測試,并以測試成功的顏色顯示。

組件掃描之后就應(yīng)該是自動(dòng)裝配了。簡單來說,自動(dòng)裝配就是讓Spring自動(dòng)滿足bean依賴的一種方法,在滿足依賴的過程中,會(huì)在Spring應(yīng)用上下文中尋找匹配某個(gè)bean需求的其他bean。

為了實(shí)現(xiàn)自動(dòng)裝配,我們可以借助Spring的@Autowired注解。

考慮下面這個(gè)示例,通過自動(dòng)裝配,將一個(gè)CompactDisc注入到CDPlayer中:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
@Component
public class CDPlayer implements MediaPlayer {
  private CompactDisc cd;
 
  @Autowired
  public CDPlayer(CompactDisc cd) {
    this.cd = cd;
  }
 
  public void play() {
    cd.play();
  }
 
}

它實(shí)現(xiàn)的MediaPlayer接口:

public interface MediaPlayer {
 
  void play();
 
}

@Autowired注解不僅可以用在構(gòu)造器上,在其他方法上,Spring都會(huì)嘗試滿足方法參數(shù)上聲明的依賴。

如果沒有匹配的bean,那么在創(chuàng)建應(yīng)用上下文時(shí),Spring會(huì)拋出一個(gè)異常。

下面使用一個(gè)測試類來測試自動(dòng)裝配是否成功:

import static org.junit.Assert.*;
 
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=CDPlayerConfig.class)
public class CDPlayerTest {
 
  @Rule
  public final StandardOutputStreamLog log = new StandardOutputStreamLog();
 
  @Autowired
  private MediaPlayer player;
  
  @Autowired
  private CompactDisc cd;
  
  @Test
  public void cdShouldNotBeNull() {
    assertNotNull(cd);
  }
 
  @Test
  public void play() {
    player.play();
    assertEquals(
        "Playing Sgt. Pepper's Lonely Hearts Club Band by The Beatles",
        log.getLog());
  }
 
}

在最后的斷言中,paly()測試方法調(diào)用了CDPlayer的paly()方法,并且斷言它的行為和預(yù)期的一致。


????文章原文在這里

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,628評論 19 139
  • 1.1 Spring IoC容器和bean簡介 本章介紹了Spring Framework實(shí)現(xiàn)的控制反轉(zhuǎn)(IoC)...
    起名真是難閱讀 2,674評論 0 8
  • 1.1 spring IoC容器和beans的簡介 Spring 框架的最核心基礎(chǔ)的功能是IoC(控制反轉(zhuǎn))容器,...
    simoscode閱讀 6,851評論 2 22
  • 本章內(nèi)容: 聲明Bean 構(gòu)造器注入和Setter方法注入 裝配Bean 控制bean的創(chuàng)建和銷毀 任何一個(gè)成功的...
    謝隨安閱讀 1,751評論 0 9
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,276評論 6 342

友情鏈接更多精彩內(nèi)容