- 創造application中DI本質的行為稱為wiring
- Spring configuration options
- Spring container負責創建application中的bean。並且通過DI協調之間的關西
- 需要告訴Spring哪些bean如何將其wiring在一起
- wiring mechanisms(選擇方式可以互相搭配)
- 顯式在XML中配置 (最末)
- 顯式在JAVA中配置 (次之)
- 隱式的bean自動wiring及discovery (盡可能使用)
- Automatically wiring beans 自動裝配bean
- 實現automatically wiring beans有兩種方法,且能夠搭配使用
- component scanning: Spring自動發現application context建立的bean
- autowiring: Spring自動滿足bean間的依賴
- 範例:
- 若要實現CD player依賴CD,可使用以下範例
package soundsystem; public interface CompactDisc { // 一個interface將CD player的implements和CD的coupling降至最低 void play(); }
- 建立一個具體的object
package soundsystem; import org.springframework.stereotype.Component; @Component // 表明是component,Spring會為這個class建立bean 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); } }
- 但是Component scanning預設並沒有啟用,所以需要寫明configuration,如此的話可以命令去找帶有@Component的class,即能建立bean
package soundsystem; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration
@ComponentScan// 默認會找和這個config相同的package(這邊是soundsystem)及package底下的class,找有@Component註解的class public class CDPlayerConfig { }
- XML也能夠啟用ComponentScan
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans
...
- 接著即可unit test進行測試
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) // 測試開始自動創建Spring application context @ContextConfiguration(classes=CDPlayerConfig.class) //使用的
configuration class public class CDPlayerTest { @Autowired // 將compact disc bean inject至測試code,這樣就不用寫new
private CompactDisc cd; @Test public void cdShouldNotBeNull() { assertNotNull(cd); // Spring context中創建bean並inject至此 } }
- 所有帶有@Component annotation的class都會創建bean
- 為component-scanned bean命名
- Spring application context會給所有的bean一個ID,若沒有明確給定ID,Spring會根據class name指定一個ID。而這個ID就是class name的小寫
- 給定方法:
- 在@Component括號內加上值如: @Component("lonelyHeartsClub")
- 使用@Named annotation: @Named("lonelyHeartsClub")
- 設定component scanning的base package
- Component scanning 默認會找和這個config class相同的package當作base package來做component scanning
- 問:
- 若config class的package和想要做component scanning 的package不同時,就不能使用default base package
- 解:
- 在ComponentScan括號內加上值如:
@Configuration @ComponentScan("soundsystem") public class CDPlayerConfig {}
- 也可以設定這個value是屬於base package,甚至可以設定多筆
@Configuration @ComponentScan(basePackages={"soundsystem", "video"})
public class CDPlayerConfig {}
- 也可以設定class符合type-safe,這些class所在的base package將成為component scan的base packages
@Configuration @ComponentScan(basePackageClasses={CSPlayer.class, DVDPlayer.class)
public class CDPlayerConfig {}
- Automatically wired
- 讓Spring自動尋找application context內來滿足bean依賴其他bean的方法
- 進行auto wired,使用@Autowired annotation
- 如下:
package soundsystem; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class CDPlayer implements MediaPlayer { private CompactDisc cd; @Autowired // 自動進行initialize CompactDisc並inject一個CompactDisc bean
public CDPlayer(CompactDisc cd) { this.cd = cd; } public void play() { cd.play();
}
@Autowired // 也能用在setter method上,或任何method上
public void setCompactDisc(CompactDisc cd)() {
this.cd = cd;
}
}
- Spring會嘗試滿足method上parameter所declare的dependency
- 如果只有一個bean符合,那麼將是這個bean傳入
- 如果沒有符合的,Spring會throw exception
- 解決: @Autowired(required=false)
- 但這時候這個object就會是null
- 如果有多個bean符合,Spring也會throw exception
- 可以使用@Inject代替@Autowired
沒有留言:
張貼留言