Spring容器負責建立應用程序中的bean並經過DI來協調這些對象之間的關係。當描述bean如何進行裝配時,Spring具備很是大的靈活性,它提供了三種主要的裝配機制:html
在XML中進行顯式配置java
在Java中進行顯式配置git
隱式的bean發現機制和自動裝配github
儘量地使用自動配置的機制。顯式配置越少越好。當你必需要顯式配置bean的時候(好比,有些源碼不是由你來
維護的,而當你須要爲這些代碼配置bean的時候),推薦使用類型安全而且比XML更增強大的JavaConfig。最後,只有想要使用便利的XML命名空間,而且在JavaConfig中沒有一樣的實現時,才應該使用XMLspring
Spring從兩個角度來實現自動化裝配:數組
組件掃描(component scanning):Spring會自動發現應用上下文中所建立的bean安全
自動裝配(autowiring):Spring自動知足bean之間的依賴ide
組件掃描和自動裝配組合在一塊兒就能發揮出強大的威力,它們可以將顯式配置下降到最少測試
package soundsystem; public interface CompactDisc { void play(); }
CompactDisc的具體內容並不重要,重要的是你將其定義爲一個接口。做爲接口,它定義了CD播放器對一盤CD所能進行的操做。它將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註解。這個簡單的註解代表SgtPeppers類會做爲組件類,並告知Spring要爲這個類建立bean。沒有必要顯式配置SgtPeppersbean,由於這個類使用了@Component註解,因此Spring會爲你把事情處理穩當
不過,組件掃描默認是不啓用的。咱們還須要顯式配置一下Spring,從而命令它去尋找帶有@Component註解的類,併爲其建立bean
如下程序的配置類展示了完成這項任務的最簡潔配:
package soundsystem; import org.springframework.context.annotation.componentScan; import org.springframework.context.annotation.Con; @Component @ComponentScan public class CDPlayerConfig{}
類CDPlayerConfig經過Java代碼定義了Spring的裝配規則。觀察可知,CDPlayerConfig類並無顯式地聲明任何bean,只不過它使用了@ComponentScan註解,這個註解可以在Spring中啓用組件掃描
若是沒有其餘配置的話,@ComponentScan默認會掃描與配置類相同的包。由於CDPlayerConfig類位於soundsystem包中,所以Spring將會掃描這個包以及這個包下的全部子包,查找帶有@Component註解的類。這樣的話,就能發現CompactDisc,而且會在Spring中自動爲其建立一個bean
如更傾向於使用XML來啓用組件掃描的話,那麼可使用Spring context命名空間的<context:component-scan>元素。如下程序展現了啓用組件掃描的最簡潔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/comtext" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/beans/context http://www.springframework.org/schema/beans/context/spring-context.xsd"> <context:component-scan base-package="soundsystem"/> </beans>
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_139772[test] public void cdShouldNotBeNull() { assertNotNull(cd); } }
CDPlayerTest使用了Spring的SpringJUnit4ClassRunner,以便在測試開始的時候自動建立Spring的應用上下文。註解@ContextConfiguration會告訴它須要在CDPlayerConfig中加載配置。由於CDPlayerConfig類中包含了@ComponentScan,所以最終的應用上下文中應該包含CompactDiscbean
在測試代碼中有一個CompactDisc類型的屬性,而且這個屬性帶有@Autowired註解,以便於將CompactDiscbean
注入到測試代碼之中。最後,會有一個簡單的測試方法斷言cd屬性不爲null。若是它不爲null的話,就意味着Spring可以發現CompactDisc類,自動在Spring上下文中將其建立爲bean並將其注入到測試代碼之中
Spring應用上下文中全部的bean都會給定一個ID。前面的例子中,儘管沒有明確地爲SgtPeppersbean設置ID,但Spring會根據類名爲其指定一個ID。具體來說,這個bean所給定的ID爲sgtPeppers,也就是將類名的第一個字母變爲小寫
若想爲這個bean設置不一樣的ID,則需將指望的ID做爲值傳遞給@Component註解:
@Component("lonelyHeartsClub") public class SgtPeppers implements CompactDisc { ... }
另一種爲bean命名的方式,使用Java依賴注入規範(Java Dependency Injection)中所提供的@Named註解來爲bean設置ID:
package soundsystem; import javax.inject.Named; @Named("lonelyHeartsClub") public class SgtPeppers implements CompactDisc { ... }
爲了指定不一樣的基礎包,所須要在@ComponentScan的value屬性中指明包的名稱:
@Configuration @ComponentScan("soundsystem") public class CDPlayerConfig{}
若需更加清晰地代表你所設置的是基礎包,經過basePackages屬性進行配置:
@Configuration @ComponentScan(basePackages = "soundsystem") public class CDPlayerConfig{}
若是須要能夠設置多個基礎包,只須要將basePackages屬性設置爲要掃描包的一個數組便可:
@Configuration @ComponentScan(basePackages = {"soundsystem", 「videos」}) public class CDPlayerConfig{}
上面例子中,所設置的基礎包是以String類型表示的。這是可行的,但這種方法是類型不安全(not type-safe)的。如進行代碼重構,那麼所指定的基礎包可能會出現錯誤
除了將包設置爲簡單的String類型以外,@ComponentScan提供的另一種方法,將其指定爲包中所包含的類或接口:
@Configuration @ComponentScan(basePackageClasses = {CDPlayer.class, DVDPlayer.class}) public class CDPlayerConfig{}
自動裝配就是讓Spring自動知足bean依賴的一種方法,在知足依賴的過程當中,會在Spring應用上下文中尋找匹配某個bean需求的其餘bean。爲了聲明要進行自動裝配,咱們能夠藉助Spring的@Autowired註解
下述程序CDPlayer類。它的構造器上添加了@Autowired註解,這代表當Spring建立CDPlayerbean的時候,會經過這個構造器來進行實例化而且會傳入一個可設置給CompactDisc類型的bean
經過自動裝配,將一個CompactDisc注入到CDPlayer之中:
package soundsystem; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class CDPlayer implement MediaPlayer { private CompactDisc cd; @Autowired public CDPlayer(CompactDisc cd) { this.cd = cd; } public void play { cd.play(); } }
@Autowired註解不只可以用在構造器上,還能用在屬性的Setter方法上。好比說,若是CDPlayer有一個setCompactDisc()方法,那麼能夠採用以下的註解形式進行自動裝配:
@Autowired public void setCompactDisc(CompactDisc cd)
@Autowired註解能夠用在類的任何方法上。假設CDPlayer類有一個insertDisc()方法,那麼@Autowired可以像在setCompactDisc()上那樣,發揮徹底相同的做用:
@Autowired public void insertDisc(CompactDisc cd) { this.cd = cd; }
無論是構造器、Setter方法仍是其餘的方法,Spring都會嘗試知足方法參數上所聲明的依賴。假若有且只有一個bean匹配依賴需求的話,那麼這個bean將會被裝配進來
若是沒有匹配的bean,那麼在應用上下文建立的時候,Spring會拋出一個異常。爲了不異常的出現,你能夠將@Autowired的required屬性設置爲false:
@Autowired public CDPlayer(CompactDisc cd) { this.cd = cd; }
將required屬性設置爲false時,Spring會嘗試執行自動裝配,若沒有匹配的bean,Spring將會讓這個bean處於未裝配的狀態。但把required屬性設置爲false時,須要謹慎對待。若是代碼中沒有進行null檢查,處於未裝配狀態的屬性可能出現NullPointerException
@Autowired是Spring特有的註解。若是不肯代碼中處處使用
Spring的特定註解來完成自動裝配任務,可考慮替換爲@Inject:
package soundsystem; import javax.inject.Inject; import javax.inject.Named; @Named public class CDPlayer { ... @Inject public CDPlayer(CompactDisc cd) { this.cd = cd; } ... }
@Inject註解來源於Java依賴注入規範,該規範同時還定義了@Named註解。在自動裝配中,Spring同時支持@Inject和
@Autowired。儘管@Inject和@Autowired之間有着一些細微的差異,可是在大多數場景下,是能夠互相替換的
除了注入CompactDisc,還將CDPlayerbean注入到測試代碼的player成員變量之中(它是更爲通用的MediaPlayer類型)。在play()測試方法中,咱們能夠調用CDPlayer的play()方法,並斷言它的行爲與預期一致
在測試代碼中使用System.out.println()。所以,該樣例中使用了StandardOutputStreamLog,是來源於System Rules庫(http://stefanbirkner.github.i...)的一個JUnit規則,該規則可以基於控制檯的輸出編寫斷言。SgtPeppers.play()方法的輸出將被髮送到控制檯上
如想將第三方庫中的組件裝配到你的應用中,在這種狀況下沒法經過在它的類上添加@Component和@Autowired註解的方法實現自動化裝配
JavaConfig與其餘的Java代碼存在區別,在概念上,它與應用程序中的業務邏輯和領域代碼不一樣的。儘管都使用相同的語言進行表述,但JavaConfig是配置代碼。這意味着它不該該包含任何業務邏輯,JavaConfig也不該該侵入到業務邏輯代碼之中。儘管不是必須的,但一般會將JavaConfig放到單獨的包中,使它與其餘的應用程序邏輯分離開來,這樣對於它的意圖就不會產生困惑了
建立JavaConfig類的關鍵在於爲其添加@Configuration註解,@Configuration註解代表這個類是一個配置類,該類應該包含在Spring應用上下文中如何建立bean的細節
package soundsystem; import org.springframework.context.annotation.Configuration; @Configuration public class CDPlayerConfig { ... }
到此爲止,都是依賴組件掃描來發現Spring應該建立的bean。儘管能夠同時使用組件掃描和顯式配置,但在本節更加關注於顯式配置,所以將CDPlayerConfig的@ComponentScan註解移除掉了。移除了@ComponentScan註解,此時的CDPlayerConfig類就沒有任何做用了。如如今運行CDPlayerTest,測試失敗,並出現BeanCreation-Exception異常。測試指望被注入CDPlayer和CompactDisc,但這些bean根本就沒有建立,由於組件掃描不會發現它們。下一節,將展示如何使用JavaConfig裝配CDPlayer和CompactDisc
要在JavaConfig中聲明bean,需編寫一個建立所需類型實例的方法,而後給這個方法添加@Bean註解。以下代碼聲明瞭CompactDisc bean:
@Bean public CompactDisc sgtPeppers() { return new SgtPeppers(); }
@Bean註解會告訴Spring這個方法將會返回一個對象,該對象要註冊爲Spring應用上下文中的bean。方法體中包含了最終產生bean實例的邏輯
默認狀況下,bean的ID與帶有@Bean註解的方法名是同樣的。在本例中,bean的名字將會是sgtPeppers。若是你想爲其設置成一個不一樣的名字的話,那麼能夠重命名該方法,也能夠經過name屬性指定一個不一樣的名字:
@Bean(name= "lonelyHeartsClubBand") public CompactDisc sgtPeppers() { return new SgtPeppers(); }
前面所聲明的CompactDisc bean很是簡單,自身沒有其餘依賴。如今,須要聲明依賴於CompactDisc的CDPlayer bean。在JavaConfig中裝配bean的最簡單方式就是引用建立bean的方法。以下就是一種聲明CDPlayer的可行方案:
@Bean public CDPlayer cdPlayer() { return new CDPlayer(sgtPeppers()); }
這個方法會建立一個bean實例並將其註冊到Spring應用上下文中。所建立的bean ID爲cdPlayer,與方法的名字相同。cdPlayer()的方法體與sgtPeppers()稍微有些區別。在這裏並無使用默認的構造器構建實例,而是調用了須要傳入CompactDisc對象的構造器來建立CDPlayer實例。看起來,CompactDisc是經過調用sgtPeppers()獲得的,但狀況並不是徹底如此。由於sgtPeppers()方法上添加了@Bean註解,Spring將會攔截全部對它的調用,並確保直接返回該方法所建立的bean,而不是每次都對其進行實際的調用
@Bean public CDPlayer cdPlayer() { return new CDPlayer(sgtPeppers()); } @Bean public CDPlayer anotherCDPlayer() { return new CDPlayer(sgtPeppers()); }
默認狀況下,Spring中的bean都是單例的,並不必爲第二個CDPlayer bean建立徹底相同的SgtPeppers實例。因此,Spring會攔截對sgtPeppers()的調用並確保返回的是Spring所建立的bean,也就是Spring自己在調用sgtPeppers()時所建立的CompactDiscbean。所以,兩個CDPlayer bean會獲得相同的SgtPeppers實例
@Bean public CDPlayer cdPlayer(CompactDisc compactDisc) { return new CDPlayer(sgtPeppers()); }
在這裏,cdPlayer()方法請求一個CompactDisc做爲參數。當Spring調用cdPlayer()建立CDPlayerbean的時候,它會自動裝配一個CompactDisc到配置方法之中。而後,方法體就能夠按照合適的方式來使用它。藉助這種技術,cdPlayer()方法也可以將CompactDisc注入到CDPlayer的構造器中,並且不用明確引用CompactDisc的@Bean方法
經過這種方式引用其餘的bean一般是最佳的選擇,由於它不會要求將CompactDisc聲明到同一個配置類之中。在這裏甚至沒有要求CompactDisc必需要在JavaConfig中聲明,實際上它能夠經過組件掃描功能自動發現或者經過XML來進行配置
能夠將配置分散到多個配置類、XML文件以及自動掃描和裝配bean之中,只要功能完整健全便可。無論CompactDisc是採用什麼方式建立出來的,Spring都會將其傳入到配置方法中,並用來建立CDPlayer bean
在使用XML爲Spring裝配bean以前,你須要建立一個新的配置規範。在使用JavaConfig的時候,這意味着要建立一個帶有@Configuration註解的類,而在XML配置中,這意味着要建立一個XML文件,而且要以<beans>元素爲根
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/beans/context"> <!-- configuration details go here --> </beans>
如上基本的XML配置已比同等功能的JavaConfig類複雜。在JavaConfig中只須要@Configuration,但在XML中,須要在配置文件的頂部聲明多個XML模式(XSD)文件,這些文件定義了配置Spring的XML元素
藉助Spring Tool Suite建立XML配置文件建立和管理Spring XML配置文件的一種簡便方式是使用Spring Tool Suite(https://spring.io/tools/sts)。在Spring Tool Suite的菜單中,選擇File>New>Spring Bean Configuration File,可以建立Spring XML配置文件,而且能夠選擇可用的配置命名空間
用來裝配bean的最基本的XML元素包含在spring-beans模式之中,在上面這個XML文件中,它被定義爲根命名空間。<beans>是該模式中的一個元素,它是全部Spring配置文件的根元素
要在基於XML的Spring配置中聲明一個bean,咱們要使用springbeans模式中的另一個元素:<bean>。<bean>元素相似於JavaConfig中的@Bean註解。能夠以下的方式聲明CompactDiscbean:
<bean class="soundsystem.SgtPeppers" />
這裏聲明瞭一個簡單的bean,建立這個bean的類經過class屬性來指定的,而且要使用全限定的類名
因沒明確給定ID,因此這個bean將會根據全限定類名來進行命名。在本例中,bean的ID將會是「soundsystem.SgtPeppers#0」。其中,「#0」是一個計數的形式,用來區分相同類型的其餘bean。若是你聲明瞭另一個SgtPeppers,而且沒有明確進行標識,那麼它自動獲得的ID將會是「soundsystem.SgtPeppers#1」
一般來說,更好的辦法是藉助id屬性,爲每一個bean設置一個你本身選擇的名字:
<bean id = "compactDisc" class="soundsystem.SgtPeppers" />
減小繁瑣爲了減小XML中繁瑣的配置,只對那些須要按名字引用的bean(好比,你須要將對它的引用注入到另一個bean中)進行明確地命名
藉助IDE檢查XML的合法性使用可以感知Spring功能的IDE,如Spring Tool Suite,可以在很大程度上幫助你確保Spring XML配置的合法性
在Spring XML配置中,只有一種聲明bean的方式:使用<bean>元素並指定class屬性。Spring會從這裏獲取必要的信息來建立bean。可是,在XML中聲明DI時,會有多種可選的配置方案和風格。具體到構造器注入,有兩種基本的配置方案可供選擇:
<constructor-arg>元素
使用Spring 3.0所引入的c-命名空間
1.<constructor-arg>元素方案:
現已聲明SgtPeppers bean,而且SgtPeppers類實現了CompactDisc接口,因此實際上已經一個能夠注入到CDPlayerbean中的bean。所需作的是在XML中聲明CDPlayer並經過ID引用SgtPeppers:
<bean id="cdplayer" class="soundsystem.CDPlayer"> <constructor-arg ref="compactDisc" /> </bean>
當Spring遇到這個<bean>元素時,會建立一個CDPlayer實例。<constructor-arg>元素會告知Spring要將一個ID
爲compactDisc的bean引用傳遞到CDPlayer的構造器中
2.c-命名空間方案:
c-命名空間是在XML中更爲簡潔地描述構造器參數的方式。要使用它的話,必需要在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:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="bar" class="x.y.Bar"/> <bean id="baz" class="x.y.Baz"/> <!-- 標準XML格式 --> <bean id="foo" class="x.y.Foo"> <constructor-arg name="bar" ref="bar"/> <constructor-arg name="baz" ref="baz"/> <constructor-arg name="email" value="foo@bar.com"/> </bean> <!-- c命名空間格式 --> <bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"/> <!-- 還可使用c命名空間的參數索引格式 --> <bean id="foo" class="x.y.Foo" c:_0-ref="bar" c:_1-ref="baz" c:_2="foo@bar.com"/> </beans>
在c-命名空間和模式聲明以後,就可使用它來聲明構造器參數了,以下所示:
<bean id="cdplayer" class="soundsystem.CDPlayer" c:cd-ref="compactDisc" />
屬性名以「c:」開頭,也就是命名空間的前綴。接下來就是要裝配的構造器參數名,在此以後是「-ref」,這是一個命名的約定,它會告訴Spring,正在裝配的是一個bean的引用,這個bean的名字是compactDisc,而不是字面量「compactDisc」
引用參數的名稱有些怪異,由於須要編譯代碼時,將調試標誌(debug symbol)保存在類代碼中。若是優化構建過程,將調試標誌移除掉,那麼這種方式可能就沒法正常執行。根本不用去標示參數的方案:
<bean id="cdplayer" class="soundsystem.CDPlayer" c:_-ref="compactDisc" />
迄今爲止,所作的DI一般指的都是類型的裝配——也就是將對象的引用裝配到依賴於它們的其餘對象之中——而有時須要的只是用一個字面量值來配置對象
1.<constructor-arg>元素方案:
package soundsystem; public class BlankDisc implements CompactDisc { private String title; private String artist; public BlankDisc(String title, String artist) { this.title = title; this.artist = artist; } public void play() { System.out.println("Playing" + title + "by" + artist); } }
<bean id="compactDisc" class="soundsystem.BlankDisc"> <constructor-arg value = "Sgt. Pepper's Lonely Hearts Club Band" /> <constructor-arg value = "The Beatles" /> </bean>
上述程序使用<constructor-arg>元素進行構造器參數的注入。沒有使用「ref」屬性來引用其餘的bean,而使用了
value屬性,經過該屬性代表給定的值要以字面量的形式注入到構造器之中
2.c-命名空間方案:
引用構造器參數名:
<bean id="compactDisc" class="soundsystem.BlankDisc" c:_title="Sgt. Pepper's Lonely Hearts Club Band" c:_artist="The Beatles" />
經過參數索引裝配相同的字面量值:
<bean id="compactDisc" class="soundsystem.BlankDisc" c:_0="Sgt. Pepper's Lonely Hearts Club Band" c:_1="The Beatles" />
含有磁道列表概念的BLankDisc
package soundsystem.collections; import java.ytil.List; import soundsystem.CompactDisc; public class BlankDisc implements CompactDisc { private String title; private String artist; private List<String> tracks; public BlankDisc(String title, String artist, List<String> tracks) { this.title = title; this.artist = artist; this.tracks = tracks; } public void play() { System.out.println("Playing" + title + "by" + artist); for(String track : tracks) { System.out.println("-Track: " + track); } } }
這個變動會對Spring如何配置bean產生影響,在聲明bean時,必需要提供一個磁道列表。較好的解決方法是提供一個磁道名稱的列表。首先,可使用<list>元素將其聲明爲一個列表:
<bean id="compactDisc" class="soundsystem.BlankDisc"> <constructor-arg value = "Sgt. Pepper's Lonely Hearts Club Band" /> <constructor-arg value = "The Beatles" /> <constructor-arg> <list> <value>Sgt. Pepper's Lonely Hearts Club Band</value> <value>With a Little Help from My Friend</value> <value>Lucy in the Sky with Diamonds</value> <value>Getting Better</value> <value>Fixing a Hole</value> <!-- ...other tracks omiitted for brevity... -> </list> </constructor-arg> </bean>
其中,<list>元素是<constructor-arg>的子元素,這代表一個包含值的列表將會傳遞到構造器中。其中,<value>元素用來指定列表中的每一個元素
也可以使用<ref>元素替代<value>,實現bean引用列表的裝配。假設有一個Discography類,構造器以下所示:
public Discography(String artist, List<CompactDisc> cds) { ... }
採起以下的方式配置Discography bean:
<bean id="beatlesDiscography" class="soundsystem.Discography"> <constructor-arg value = "The Beatles" /> <constructor-arg> <list> <ref bean="SgtPeppers" /> <ref bean="whiteAlbum" /> <ref bean="hardDaysNight" /> <ref bean="revolver" /> ... </list> </constructor-arg> </bean>
在裝配集合方面,<constructor-arg>比c-命名空間的屬性更有優點。目前,使用c-命名空間的屬性沒法實現裝配集合的功能。使用<constructor-arg>和c-命名空間實現構造器注入時,它們之間還有一些細微的差異
設屬性注入的CDPlayer以下所示:
package soundsystem; import org.springframework.beans.factory.annotation.Autowired; import soundsystem.CompactDisc; import soundsystem.MediaPlayer; public class CDPlayer implement MediaPlayer { private CompactDisc compactDisc; @Autowired public CDPlayer(CompactDisc compactDisc) { this.compactDisc = compactDisc; } public void play { compactDisc.play(); } }
做爲一個通用的規則,強依賴使用構造器注入,而對可選性的依賴使用屬性注入
p-命名空間:
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 標準XML格式 --> <bean name="john-classic" class="com.example.Person"> <property name="name" value="John Doe"/> <property name="spouse" ref="jane"/> </bean> <!-- p命名空間格式 --> <bean name="john-modern" class="com.example.Person" p:name="John Doe" p:spouse-ref="jane"/> </beans>
使用p-命名空間裝配compactDisc屬性:
<bean id = "cdplayer" class = "soundsystem.CDPlayer" p:compactDisc-ref = "compactDisc" />
屬性的名字使用了「p:」前綴,代表咱們所設置的是一個屬性。接下來就是要注入的屬性名。最後,屬性的名稱以「-ref」結尾,這會提示Spring要進行裝配的是引用,而不是字面量
如下BlankDisc徹底經過屬性注入進行配置,而不是構造器注入。新的BlankDisc類以下所示:
package soundsystem.collections; import java.ytil.List; import soundsystem.CompactDisc; public class BlankDisc implements CompactDisc { private String title; private String artist; private List<String> tracks; public setTitle(String title) { this.title = title; } public setArtistString artist) { this.artist = artist; } public setTracks(List<String> tracks) { this.tracks = tracks; } public void play() { System.out.println("Playing" + title + "by" + artist); for(String track : tracks) { System.out.println("-Track: " + track); } } }
藉助<property>元素的value屬性裝配這些屬性,內嵌<list>元素設置tracks屬性:
<bean id="compactDisc" class="soundsystem.BlankDisc"> <property name = "title" value = "Sgt. Pepper's Lonely Hearts Club Band" /> <property name = "artist" value = "The Beatles" /> <property name = "tracks"> <list> <value>Sgt. Pepper's Lonely Hearts Club Band</value> <value>With a Little Help from My Friend</value> <value>Lucy in the Sky with Diamonds</value> <value>Getting Better</value> <value>Fixing a Hole</value> <!-- ...other tracks omiitted for brevity... -> </list> </property> </bean>
使用p-命名空間:
<bean id = "compactDisc" class="soundsystem.BlankDisc" p:title = "Sgt. Pepper's Lonely Hearts Club Band" p:artist = "The Beatles"> <property name = "tracks"> <list> <value>Sgt. Pepper's Lonely Hearts Club Band</value> <value>With a Little Help from My Friend</value> <value>Lucy in the Sky with Diamonds</value> <value>Getting Better</value> <value>Fixing a Hole</value> <!-- ...other tracks omiitted for brevity... -> </list> </property> </bean>
與c-命名空間同樣,裝配bean引用與裝配字面量的惟一區別在因而否帶有「-ref」後綴。若是沒有「-ref」後綴的話,所裝配的就是字面量
不能使用p-命名空間來裝配集合,沒有便利的方式使用p-命名空間來指定一個值(或bean引用)的列表。但可使用Spring util-命名空間中的一些功能來簡化BlankDiscbean
首先,須要在XML中聲明util-命名空間及其模式:
<?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:p="http://www.springframework.org/schema/p" xmlns:util="http://http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> ... </beans>
util-命名空間所提供的功能之一就是<util:list>元素,它會建立一個列表的bean。<util:list>可將磁道列表轉移到BlankDisc bean以外,並將其聲明到單獨的bean之中,以下所示:
<util:list id = "trackList"> <value>Sgt. Pepper's Lonely Hearts Club Band</value> <value>With a Little Help from My Friend</value> <value>Lucy in the Sky with Diamonds</value> <value>Getting Better</value> <value>Fixing a Hole</value> <!-- ...other tracks omiitted for brevity... -> </util:list>
將磁道列表bean注入到BLANkDisc bean的tracks屬性中:
<bean id = "compactDisc" class = "soundsystem.BlankDisc" p:title = "Sgt. Pepper's Lonely Hearts Club Band" p:artist = "The Beatles" p:tracks-ref = "trackList" />
元素 | 描述 |
---|---|
<util:constant> | 引用某個類型的public static域,並將其暴露爲bean |
<util:list> | 建立一個java.util.List類型的bean,其中包含值或引用 |
<util:map> | 建立一個java.util.Map類型的bean,其中包含值或引用 |
<util:properties> | 建立一個java.util.properties類型的bean |
<util:property-path> | 引用一個bean的屬性(或內嵌屬性),並將其暴露爲bean |
<util:set> | 建立一個java.util.Set類型的bean,其中包含值或引用 |
如今假設CDPlayerConfig已經有些笨重,所以將其進行拆分。雖然目前只定義了兩個bean,遠遠稱不上覆雜Spring配置。不過,在此假設兩個bean已經算多了。一種方案是將BlankDisc從CDPlayerConfig拆分出來,定義到它本身的CDConfig類中,以下所示:
package soundsystem; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class CDConfig { @Bean public CompactDisc compactDisc() { return new SgtPeppers(); } }
上述程序的compactDisc()方法已經從CDPlayerConfig中移除掉了,現須要將這兩個類組合在一塊兒。一種方法就是
在CDPlayerConfig中使用@Import註解導入CDConfig:
package soundsystem; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import(CDConfig.class) public class CDPlayerConfig { @Bean public CDPlayer cdPlayer(CompactDisc compactDisc) { return new CDPlayer(compactDisc); } }
更好的辦法,不在CDPlayerConfig中使用@Import,而是建立一個更高級別的SoundSystemConfig,在
這個類中使用@Import將兩個配置類組合在一塊兒:
package soundsystem; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import(CDConfig.class) public class CDPlayerConfig { @Bean public CDPlayer cdPlayer(CompactDisc compactDisc) { return new CDPlayer(compactDisc); } }
更好的辦法,不在CDPlayerConfig中使用@Import,而是建立一個更高級別的SoundSystemConfig,在這個類中使用@Import將兩個配置類組合在一塊兒:
package soundsystem; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import({CDPlayerConfig.class, CDConfig.class}) public class SoundSystemConfig { }
現已將CDPlayer的配置與BlankDisc的配置分開,假設(基於某些緣由)但願經過XML來配置BlankDisc,以下所示:
<bean id="compactDisc" class="soundsystem.BlankDisc"> <c:_0 = "Sgt. Pepper's Lonely Hearts Club Band" /> <c:_1 = "The Beatles" /> <constructor-arg> <list> <value>Sgt. Pepper's Lonely Hearts Club Band</value> <value>With a Little Help from My Friend</value> <value>Lucy in the Sky with Diamonds</value> <value>Getting Better</value> <value>Fixing a Hole</value> <!-- ...other tracks omiitted for brevity... -> </list> </constructor-arg> </bean>
使用@ImportResource註解同時加載XML配置和其餘基於Java的配置,假設BlankDisc定義在名爲cdconfig.
xml的文件中,該文件位於根類路徑下,那麼能夠修改SoundSystemConfig,讓它使用@ImportResource註解,以下所示:
package soundsystem; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import(CDPlayerConfig.class) @ImportResource("classpath:cd-config.xml") public class SoundSystemConfig { }
在JavaConfig配置中,使用@Import和@ImportResource來拆分JavaConfig類。在XML中,使用import元素來拆分XML配置
設但願將BlankDisc bean拆分到本身的配置文件中,該文件名爲cd-config.xml,這與以前使用@ImportResource是同樣的。課在XML配置文件中使用<import>元素來引用該文件:
<?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:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <import resoune = "cd-config.xml"/> <bean id = "cdPlayer" class = "soundsystem.CDPlayer" c:cd-ref = "compactDisc"/> </beans>