Spring實戰:裝配bean-自動化裝配bean

MurasakiSeiFu發表於2018-01-27

自動化裝配 bean

  • Spring 從兩個角度實現自動化裝配:

    • 元件掃描(Component scanning):Spring會自動發現應用上下文中所建立的bean。
    • 自動裝配(autowiring):Spring自動滿足bean之間的依賴。
建立可被發現的 bean

CD 為我們闡述依賴注入是如何執行的。如果你不將CD插入(注入)到CD播放器中,那麼CD播放器沒有什麼太大用處。所以,可以說,CD播放器依賴於CD才能完成它的使命。
首先,我們定義一個CD的概念,一個介面:

package soundsystem;

public interface CompactDisc {
  void play();
}

作為介面,它定義了CD播放器對一盤CD所能進行的操作。我們現在還需要一個實現類。

package soundsystem;
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.println("Playing " + title + " by " + artist);
  }
}

SgtPeppers類上使用了 @Component 註解。
@Component:這個註解表明該類回座位元件類,並告知Spring要為這個類建立bean。

不過,元件掃描預設是不啟用的。我們還需要顯示配置一下spring,從而命令它去尋找帶有@Component註解的類,併為其建立bean。

package soundsystem;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class CDPlayerConfig {
}

CDPlayerConfig類並沒有顯示地宣告任何bean,只不過它使用了@ComponentScan註解,這個註解能夠在Spring中啟用元件掃描。如果沒有其他配置的話,@ComponentScan預設會掃描與配置類相同的包。
測試類做一個簡單的測試。

package soundsystem;

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);
  }
}

註解 @ContextConfiguration 會告訴它需要在 CDPlayerConfig 中載入配置。因為 CDPlayerConfig 類中包含了 @ComponentScan ,因此最終的應用上下文中應該包含 CompactDisc bean。

為元件掃描的bean命名

Spring應用上下文中所有的bean都會給定一個ID。預設為會根據類名指定一個ID,也就是將類名的首字母變為小寫。如果想單獨設定ID可以在後追加名稱

@Component("xxxxxx")
設定元件掃描的基礎包

我們沒有為 @ComponentScan 設定任何屬性,按照預設規則,它會以配置類所在的包作為基礎包(base package)來掃描元件,如果我們想掃描不同的包,我們可以在 @ComponentScan 的 value 屬性中指明包的名稱:

@Configuration
@ComponentScan("soundsystem")
public class CDPlayerConfig {} 

如果你想更加清晰地表明你所設定的死基礎包,那麼你可以通過 basePackages 屬性進行配置:

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

basePackages 屬性使用的複數形式,所以我們可以設定多個基礎包,只需要將 basePackages 屬性設定為要掃描包的一個陣列即可:

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

上面的例子是以 String 型別表示的。顯然這種方法是不安全的,如果重構程式碼的話,那麼所指定的基礎包可能就會出現錯誤。所以我們可以使用另外一種方法,將其指定為包中鎖包含的類或介面:

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

其實最好的方法,可以考慮在包中建立一個用來進行掃描的空標記介面,依然能夠保持對重構友好的介面引用,但是可以避免引用任何實際的應用程式程式碼。

通過為bean新增註解實現自動裝配

在你的應用程式中,如果所有物件都是獨立的,彼此之間沒有任何依賴,那麼你所需要的就只是元件掃描而已。但是,很多物件會依賴其他的物件才能完成任務。這樣的話,我們就需要一種方法能夠將元件掃描得到的 bean 和它們的依賴裝配在一起。也就是自動裝配。
簡單來說,自動裝配就是讓Spring自動滿足bean依賴的一種方法,在滿足依賴的過程中,會在Spring應用上下文中尋找匹配某個bean需求的其他bean。為了宣告要進行自動裝配,我們可以藉助Spring的 @Autowired 註解。

package soundsystem;
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();
  }
}

在構造器上加註解,表明當 Spring 建立 CDPlayer bean的時候,會通過這個構造器來進行例項化並且會傳入一個可設定給 CompactDisc 型別的bean。
不管是構造器、Setter 方法還是其他的方法,Spring 都會嘗試滿足方法引數上所宣告的依賴。假如有且只有一個bean匹配依賴需求的話,那麼這個bean將會被裝配進來。

參考
https://livebook.manning.com/…

相關文章