Spring從兩個角度來實現自動化裝配:
- 組件掃描:Spring會自動發現應用上下文中所創建的bean。
- 自動裝配:Spring自動滿足bean之間的依賴。
案例:音響系統的組件。首先為CD創建CompactDisc接口及實現類,Spring會發現它並將其創建為一個bean。然后,會創建一個CDPlayer類,讓Spring發現它,並將CompactDisc bean注入進來。
創建CompactDisc接口:
package soundsystem;
public interface CompactDisc {
void play();
}
實現CompactDisc接口:
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注解,這個注解表明該類會作為組件類,並告知Spring要為這個類創建bean,不需要顯示配置SgtPeppers bean。
不過組件掃描默認是不開啟的。我們需要顯示配置一下Spring,從而命令Spring去尋找帶有 @Component注解的類,並創建bean。
顯示配置Spring包括Java和XML兩種方式,通過Java啟用組件掃描:
package soundsystem;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan
public class CDPlayerConfig {
}
注意,類CDPlayerConfig通過Java代碼定義了Spring的裝配規則,但是可以看出並沒有顯示地聲明任何bean,只不過它使用了 @ComponentScan注解,這個注解能夠在Spring中啟用組件掃描。
如果沒有其他配置的話,@ComponentScan默認會掃描與配置類相同的包。因為CDPlayerConfig位於sound system包中,因此Spring默認將會掃描這個包以及這個包下的所有子包,查找所有帶有 @Component注解的類。這樣的話,SgtPeppers類就會被自動創建一個bean。
通過XML啟用組件掃描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans";
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
xmlns:context="http://www.springframework.org/schema/context";
xmlns:c="http://www.springframework.org/schema/c";
xmlns:p="http://www.springframework.org/schema/p";
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd">;
<context:component-scan base-package="soundsystem" />
</beans>
context:component-scan元素會有與 @ComponentScan相對應的屬性和子元素。
測試組件掃描能夠發現CompactDisc:
package soundsystem;
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 CompactDisc cd;
@Test
public void cdShouldNotBeNull() {
assertNotNull(cd);
}
}
CDPlayerTest使用了Spring的SpringJUnit4ClassRunner,以便在測試開始的時候自動創建Spring的應用上下文。注解ContextConfiguration會告訴它需要在CDPlayerConfig類中加載配置。因為CDPlayerConfig類中包含了 @ComponentScan,因此最終的應用上下文應該包含CompactDisc bean。
測試方法斷言cd屬性部位null。如果不為null。就意味着Spring能發現CompactDisc類,並自動在Spring上下文中創建為bean並注入到測試代碼中。
為組件掃描的bean命名
Spring應用上下文中所有的bean都會給定一個ID。默認bean命名為類名的第一個字母變為小寫,上面的SgtPeppers bean指定的ID為sgtPeppers。
如果想要指定bean ID,可以將ID值傳遞給 @Component注解。如下:
@Component("lonelyHeartsClub")
public class SgtPeppers implements CompactDisc {
}
設置組件掃描的基礎包
@Component注解沒有設置任何屬性的情況下,按照默認規則,Spring會以配置類所在的包作為基礎包來掃描組件。但是如果想掃描不同的包,需要做的就是
@Component的value屬性中指名包的名稱:
@Configuration
@ComponentScan("soundsystem")
public class CDPlayerConfig {
}
如果想更加清晰的表明設置的基礎包,可以通過設置basePackages屬性:
@Configuration
@ComponentScan(basePackages="soundsystem")
public class CDPlayerConfig {
}
同時basePackages支持多個基礎包的設置,屬性設置為數組即可:
@Configuration
@ComponentScan(basePackages={"soundsystem", "voice"})
public class CDPlayerConfig {
}
另外還提供一種方法,可以指定包中所含的類或接口:
@Configuration
@ComponentScan(basePackegeClasses={CDPlayer.class, DVDPlayer.class})
public class CDPlayerConfig {
}
通過為bean添加注解實現自動裝配
自動裝配就是讓Spring自動滿足bean依賴的一種方式,在滿足依賴的過程中,會在Spring的上下文中尋找匹配一個bean需求的其他bean。為了聲明要進行自動裝配,我們可以借助Spring的 @Autowried注解。
比如說CDPlayer類,它在構造器上添加了 @Autowried注解,這表明當創建CDPlayer bean的時候,會通過這個構造器來進行實例化並且會傳入一個可設置給CompactDisc類型的bean。
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();
}
}
@Autowried注解不僅能夠用在構造器上,還能用在Setter方法上。
@Autowired
public void setCompactDisc(CompactDisc cd) {
this.cd = cd;
}
事實上,@Autowried注解可以用在類的任何方法上去引入依賴的bean,Spring都會嘗試滿足方法參數上所聲明的依賴。
如果沒有匹配的bean,那么在應用上下文創建的時候,Spring會拋出一個異常。為了避免出現異常,可以將 @Autowried的required屬性設置為false:
@Autowired(required=false)
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
設置以后,會嘗試自動裝配,但是如果沒有匹配的bean,Spring默認會處於未裝配的狀態。但是把required設置為false時,需要謹慎對待,如果代碼中沒有進行null檢查的話,建議不使用,不然就會出現NullPointerException異常。
驗證自動裝配
前面我們的CDPlayerTest測試類,實現了自動裝配CompactDisc,現在我們借助CDPlayer bean播放CD,表現出依賴的自動裝配:
package soundsystem;
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\n",
log.getLog());
}
}
現在除了注入CompactDisc,還將CDPlayer bean注入到測試代碼的player成員變量中。
總結一下,自動裝配bean的過程:
一、把需要被掃描的類,添加 @Component注解,使它能夠被Spring自動發現。
二、通過顯示的設置Java代碼 @ComponentScan注解或XML配置,讓Spring開啟組件掃描,並將掃描的結果類創建bean。
三、@Autowried注解能偶實現bean的自動裝配,實現依賴注入。
轉載請注明出處。
作者:wuxiwei
出處:http://www.cnblogs.com/wxw16/p/7704204.html