當(dāng)構(gòu)造函數(shù)有2個相同類型的參數(shù),指定次序可以解決此種情況。注意index
是從0開始
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
記住砰嘁,若要使Spring能從構(gòu)造函數(shù)查找參數(shù)名字,代碼在編譯時必須開啟調(diào)試模式秉撇。若你沒有開啟調(diào)試模式(或者不想),可以使用@ConstructorProperties
JDK 注解明確指定構(gòu)造參數(shù)的name
。樣例程序:
package examples;
public class ExampleBean {
// Fields omitted
@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
<h5 id='beans-setter-injection'>setter注入</h5>
Setter注入是容器調(diào)用bean上的setter方法,bean是使用無參構(gòu)造函數(shù)返回的實例新荤,或者無參靜態(tài)工廠方法返回的實例。
下面樣例中展示了只能使用Setter注入的類台汇。這個類是傳統(tǒng)java類苛骨,就是個POJO,不依賴容器指定的接口苟呐、基類痒芝、注解。
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a setter method so that the Spring container can inject a MovieFinder
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
ApplicationContext
對它所管理的bean支持構(gòu)造注入和setter注入牵素。也支持先構(gòu)造注入再setter注入严衬。定義依賴,會轉(zhuǎn)換成某種形式的<code class="scode">BeanDefinition</code>類笆呆,<code class="scode">BeanDefinition</code>類與<code class="scode">PropertyEditor</code>實例配合请琳,即可將屬性從一種格式轉(zhuǎn)換成其他格式。然而赠幕,大多數(shù)程序員不會直接使用這些類(也就是編程式)俄精,更多的是使用XML、注解(也就是<code class="scode">@Component</code><code class="scode">@Controller</code>等等),或者<code class="scode">@Configuration</code>注解的類中的方法上使用 <code class="scode">@Bean</code>榕堰。這些配置數(shù)據(jù)嘀倒,都會在容器內(nèi)部轉(zhuǎn)換成BeanDefinition
,用于加載整個Spring Ioc 容器。
構(gòu)造注入對比setter注入
何時使用構(gòu)造注入测蘑,何時使用setter注入,經(jīng)驗法則是:強制依賴用構(gòu)造康二,可選依賴用Setter碳胳。注意,在settter方法上使用<code class="scode">@Required</code>注解即可另屬性強制依賴沫勿。
Spring 團隊建議,構(gòu)造注入的實例是不可變的挨约,不為null的。此外产雹,構(gòu)造注入組件要將完全初始化后的實例返回給客戶端代碼诫惭。還有,大量參數(shù)的構(gòu)造函數(shù)是非常爛的蔓挖,它意味著該類有大量的職責(zé)夕土,得重構(gòu)。
setter注入主要用于可選依賴,類內(nèi)部可以指定默認依賴瘟判。否則類內(nèi)所有使用依賴的地方怨绣,都得進行非空校驗。setter注入的有個好處就是拷获,類可以重配置或者再注入篮撑。因此,使用JMX MBeans
進行管理的場景中匆瓜,就非常適合setter注入赢笨。
使用何種依賴注入方式,對于某些類驮吱,非常有意義茧妒。有時協(xié)同第三方類處理,沒有源碼糠馆,由你來決定使用何種方式嘶伟。比如,第三方類未暴露任何setter方法又碌,那么構(gòu)造注入也許就是唯一的可行的注入方式了九昧。
<h5 id="beans-dependency-resolution">依賴處理過程</h5>
容器解析bean依賴如下:
-
ApplicationContext
創(chuàng)建后用配置元數(shù)據(jù)中描述的所有bean進行初始化。配置元數(shù)據(jù)格式可以是XML毕匀、Java Code铸鹰,或者注解。 - 每個bean的依賴皂岔,都會以下列形式表達:屬性蹋笼、構(gòu)造參數(shù),靜態(tài)工廠方法的參數(shù)。當(dāng)bean真正的創(chuàng)建時剖毯,這些依賴會被提供給bean圾笨。
- 每個屬性或者構(gòu)造函數(shù)或者以value值形式在bean處直接設(shè)置,或者引用容器中其他bean逊谋。
- 每一個屬性或者構(gòu)造參數(shù)都是一個值擂达,該值將會從指定的格式轉(zhuǎn)換為屬性、構(gòu)造參數(shù)的真正類型胶滋。Spring默認會將一個
String
類value轉(zhuǎn)換成內(nèi)建類型板鬓,比如int
,long
,String
,boolean
等等
Spring容器在創(chuàng)建bean之前會驗證bean的配置。在bean創(chuàng)建之前究恤,bean的屬性不會賦值俭令。當(dāng)容器創(chuàng)建之后,會創(chuàng)建被設(shè)置為預(yù)先初始化的sington-scope
單例作用域bean部宿,非單例作用域bean抄腔,只有在請求時才會創(chuàng)建。作用域窟赏,在5.5章有定義妓柜,"Bean 作用域"。一個bean的創(chuàng)建涯穷,可能會引起許多bean的創(chuàng)建棍掐。因為bean的依賴以及依賴的依賴得先創(chuàng)建好用于引用。不涉及首先創(chuàng)建的bean及其依賴類bean拷况,會稍后創(chuàng)建作煌。
循環(huán)依賴
如果你主要使用構(gòu)造注入,可能會創(chuàng)建一個循環(huán)依賴,該依賴不能解析赚瘦。
舉個栗子:類A需要類B的實例粟誓,使用了構(gòu)造注入,類B需要一個類A的實例,也用了構(gòu)造注入起意。若在配置文件中配置類A的bean和類B的bean互相注入鹰服,Spring IoC容器在運行時發(fā)現(xiàn)循環(huán)引用,拋出異常BeanCurrentlyInCreationException
揽咕。
一般使用Setter注入替代構(gòu)造注入悲酷,這需要修改源碼改配置,來解決循環(huán)依賴亲善。避免使用構(gòu)造注入或者只使用setter设易,都能避免循環(huán)依賴。 換句話說蛹头,雖然不推薦循環(huán)依賴顿肺,但是你可以使用setter注入來完成循環(huán)依賴戏溺。
和大多數(shù)場景(無循環(huán)引用)不一樣的是,循環(huán)引用中的類A和類B中屠尊,得強制其中一個自己能完全初始化旷祸,然后注入給另一個(經(jīng)典的先有雞現(xiàn)有蛋的問題)。
循環(huán)依賴end
對于Spring讼昆,你經(jīng)管放心肋僧,它非常智能。他能在容器加載期發(fā)現(xiàn)配置中的問題控淡,比如:引用了一個不存在的bean、循環(huán)依賴止潘。Spring在bean創(chuàng)建后掺炭,會盡可能遲的設(shè)置bean屬性并處理依賴。這意味著凭戴,spring容器正確加載之后涧狮,當(dāng)你請求一個對象而該對象的創(chuàng)建有問題或者是該對象的依賴有問題時,也能產(chǎn)生一個異常。舉例來說么夫,因為屬性找不到者冤,或者屬性無效, 導(dǎo)致bean拋出異常档痪。這可能會延遲發(fā)現(xiàn)配置問題涉枫,這就是為什么ApplicationContext
默認會預(yù)先實例化單例bean。在這些bean被實際請求之前就創(chuàng)建腐螟,會消耗一些時間和內(nèi)存愿汰,但是在ApplicationContext
創(chuàng)建后你就能發(fā)現(xiàn)配置問題,而不是更遲乐纸。如果你愿意 ,也可以重寫該行為衬廷,讓單例bean延遲初始化。
如果沒有循環(huán)依賴汽绢,當(dāng)一個或者多個合作bean被注入到他們的依賴類時吗跋,每一個合作bean將會比依賴類更早的實例化。也就是說宁昭,如果bean A依賴bean B跌宛,Spring Ioc容器在調(diào)用A的setter方法之前,會先實例化B久窟。換句話說秩冈,bean先實例化(非單例),然后設(shè)置依賴斥扛,然后調(diào)用相關(guān)聲明周期方法(比如配置的init方法入问,或者是初始化回調(diào)函數(shù))丹锹。
<h5 id='beans-some-examples'>注入依賴樣例</h5>
The following example uses XML-based configuration metadata for setter-based DI. A small part of a Spring XML configuration file specifies some bean definitions:
下面例子中使用了XML配置元數(shù)據(jù),setter注入方式芬失。XML 配置文件中的片段定義了bean:
<bean id="exampleBean" class="examples.ExampleBean">
<!-- 使用內(nèi)嵌的ref元素完成setter注入 -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<!-- 使用ref屬性完成setter注入 -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
看java代碼
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
}
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
}
public void setIntegerProperty(int i) {
this.i = i;
}
}
In the preceding example, setters are declared to match against the properties specified in the XML file. The following example uses constructor-based DI:
上例中楣黍,setter方法名要和XML文件中的property
元素的name
屬性相匹配。下面演示使用構(gòu)造注入 :
<bean id="exampleBean" class="examples.ExampleBean">
<!-- constructor injection using the nested ref element -->
<constructor-arg>
<ref bean="anotherExampleBean"/>
</constructor-arg>
<!-- constructor injection using the neater ref attribute -->
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg type="int" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
看java代碼
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public ExampleBean(
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
this.beanOne = anotherBean;
this.beanTwo = yetAnotherBean;
this.i = i;
}
}
在bean定義中指定的構(gòu)造函數(shù)參數(shù)棱烂,將會賦值給ExampleBean
類的參數(shù)租漂。
現(xiàn)在考慮下這個樣例的變種,將使用構(gòu)造器改為靜態(tài)工廠方法返回對象實例:
<bean id="exampleBean" class="examples.ExampleBean" factory-method="createInstance">
<constructor-arg ref="anotherExampleBean"/>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
看java代碼
public class ExampleBean {
//私有構(gòu)造函數(shù)
private ExampleBean(...) {
...
}
// 靜態(tài)工廠方法; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
public static ExampleBean createInstance (
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
ExampleBean eb = new ExampleBean (...);
// some other operations...
return eb;
}
}
靜態(tài)工廠方法的參數(shù)颊糜,應(yīng)該通過constructor-arg
元素產(chǎn)生哩治,就像是bean的構(gòu)造函數(shù)一樣.工廠方法返回的類的類型無需和工廠類類型相同,雖然本例中他們是相同的衬鱼。實例工廠方法(非靜態(tài))和靜態(tài)工廠方法本質(zhì)相同(除了使用facory-bean
屬性替代class
屬性业筏,其他都相同),因此細節(jié)就不討論了鸟赫。
<h4 id='beans-factory-properties-detailed'>依賴和配置詳解</h4>
前面章節(jié)提到的蒜胖,你可以定義的bean的屬性和構(gòu)造參數(shù)引用其他的Spring bean(合作者),或者是使用value屬性設(shè)置其值抛蚤。Spring XML格式配置元數(shù)據(jù)至此<property/>
和<constructor-arg/>
子元素台谢,用以實現(xiàn)構(gòu)造注入和屬性注入。
<h5 id="beans-value-element">直接賦值(原始類型岁经、String等等)</h5>
<property />
元素的value
屬性為對象域?qū)傩曰蛘邩?gòu)造參數(shù)設(shè)置了一個可讀的字串朋沮。Spring的會將其轉(zhuǎn)換為實際的與屬性或者參數(shù)的數(shù)據(jù)類型。
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="masterkaoli"/>
</bean>
下面的樣例蒿偎,是使用了XML配置中的p命名空間朽们,他讓XML更加簡潔
<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">
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/mydb"
p:username="root"
p:password="masterkaoli"/>
</beans>
上面的XML更簡潔;然而诉位,錯別字骑脱,要在運行期才能發(fā)現(xiàn)而不能再開發(fā)期發(fā)現(xiàn),除非你使用IDE支持自動補全苍糠。這樣的的IDE的助手真心推薦叁丧。
也可以這樣配java.unit.Properties
實例:
<bean id="mappings" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<!-- typed as a java.util.Properties -->
<property name="properties">
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
</property>
</bean>
Spring 容器通過JavaBean的PropertyEditor
機制將<value/>
元素內(nèi)的值轉(zhuǎn)換到java.util.Properties
實例。這是非常棒的岳瞭,Spring團隊最喜歡的幾處好用之處之一:用內(nèi)嵌<value/>
元素替代 值屬性風(fēng)格拥娄。
<h5 id='beans-idref-element'>元素<span class="scode">idref</span></h5>
idref
元素用來將容器內(nèi)其它bean的id傳給<constructor-arg/>
或 <property/>
元素,同時提供錯誤驗證功能瞳筏。
<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean" />
</property>
</bean>
上面的bean定義在運行時等同于下面這一段定義:
<bean id="theTargetBean" class="..." />
<bean id="client" class="...">
<property name="targetName" value="theTargetBean" />
</bean>
第一種格式比第二種要跟可取 稚瘾,因為使用idref
標簽,在開發(fā)期將允許容器校驗引用bean真是存在姚炕。在第二個中摊欠,對于client bean是屬性 targetName
的值則沒有校驗執(zhí)行 .client
bean真正的實例化時丢烘,錯別字才會被發(fā)現(xiàn)(可能會導(dǎo)致致命錯)。如果client
bean是一個原型bean些椒,這個錯字導(dǎo)致的異常也許會等到部署后才能被發(fā)現(xiàn)播瞳。
在4.0 beans xsd ,
idref
上的local
屬性不在支持免糕。因此它能提供正規(guī)bean引用 赢乓。當(dāng)你升級到4.0的語法時,記得清除已經(jīng)存在于idref
元素上的local
屬性石窑。
一個老生常談的問題(至少是2.0以前了)牌芋,<idref/>
帶來的好處,在使用ProxyFactorybean
bean定義AOP攔截器時松逊,當(dāng)指定攔截器名字是使用<idref/>
元素將姜贡,容器會校驗攔截目標是否存在。
<h5 id='beans-ref-element'>引用其他bean(協(xié)作類)</h5>
ref
元素是<constructor-arg/>
元素和<property/>
元素內(nèi)決定性元素棺棵。用它設(shè)置bean的屬性以引用另一個容器管理的bean。引用的bean就是要設(shè)置屬性的bean的依賴熄捍,在設(shè)置屬性值之前它就要被初始化烛恤。(如果協(xié)作類是單例bean,它會在容器初始化時首先完成初始化)余耽。差不多所有的bean都會引用其他對象缚柏。指定id/name
的對象的作用域和依賴校驗通過bean
,local
,parent
屬性來配置。
指定引用bean通常使用<ref/>
標簽碟贾,它允許引用本容器或者父容器中任意的bean币喧,無需配置在同一個xml文件中 。<ref/>
標簽中bean
的屬性值袱耽,使用的被引用bean的id
或者name
杀餐。
<ref bean="someBean"/>
通過指定目標bean的parent
屬性來引用當(dāng)前容器的父容器中的bean。parent
屬性的值可以和引用bean的id
或者name
(引用bean的name之一)相同朱巨,引用的bean必須存在于當(dāng)前容器的父容器中史翘。若容器存在繼承的情況,并且需要封裝現(xiàn)有父容器中的某個bean到一個代理中冀续,就可以用此種引用機制琼讽,一個與parent
bean重名的bean。
<!-- 父容器中 -->
<bean id="accountService" class="com.foo.SimpleAccountService">
<!-- 依賴 -->
</bean>
子容器中
<bean id="accountService" <!-- 和parent bean重名 -->
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref parent="accountService"/> <!--注意如何引用 parent bean -->
</property>
<!-- 其他配置和依賴 -->
</bean>
在4.0 beans xsd 洪唐,
ref
上的local
屬性不在支持钻蹬。因次它不再支持正規(guī)bean的引用 。當(dāng)你升級到到4.0時凭需,記得清除已經(jīng)存在于ref
元素上的local
屬性问欠。
<h5 id='beans-inner-beans'>內(nèi)部bean</h5>
在<property/>
元素或者constructor-arg/>
元素內(nèi)定義<bean/>
元素肝匆,就是所謂的內(nèi)部類。
<bean id="outer" class="...">
<!-- 不是引用而是定義一個bean -->
<property name="target">
<bean class="com.example.Person"> <!-- 這就是內(nèi)部類 -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>
內(nèi)部bean的定義無需id
或name
溅潜;容器會忽略這些屬性术唬。也會忽略scope
標記。內(nèi)部通常是匿名的,伴隨著外部類(的創(chuàng)建)而創(chuàng)建 滚澜。不能引用內(nèi)部bean(ref屬性不能指向內(nèi)部bean)粗仓,除非使用閉合bean
標簽。
譯者注设捐,內(nèi)部bean更直觀
fuck goods借浊,上干活
public class Customer {
private Person person;
public Customer(Person person) {
this.person = person;
}
public void setPerson(Person person) {
this.person = person;
}
@Override
public String toString() {
return "Customer [person=" + person + "]";
}
}
再來一段
public class Person {
private String name;
private String address;
private int age;
//getter and setter methods
@Override
public String toString() {
return "Person [address=" + address + ",
age=" + age + ", name=" + name + "]";
}
}
通常情況下,使用在CustomerBean
bean內(nèi)設(shè)置ref
屬性值為Person
bean的標示符萝招,即完成注入蚂斤。
<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-2.5.xsd">
<bean id="CustomerBean" class="com.example.common.Customer">
<property name="person" ref="PersonBean" />
</bean>
<bean id="PersonBean" class="com.example.common.Person">
<property name="name" value="MrChen" />
<property name="address" value="address1" />
<property name="age" value="28" />
</bean>
</beans>
In general, it’s fine to reference like this, but since the ‘MrChen’ person bean is only used for Customer bean only, it’s better to declare this ‘MrChen’ person as an inner bean as following :
一般情況下,這樣的引用很好用槐沼。但是如果'MrChen'這個person bean只用于Customer
曙蒸。最好是使用內(nèi)部bean來聲明Person
,看起來更加直觀岗钩,更具有可讀性.
<?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">
<bean id="CustomerBean" class="com.mkyong.common.Customer">
<property name="person">
<bean class="com.mkyong.common.Person">
<property name="name" value="mkyong" />
<property name="address" value="address1" />
<property name="age" value="28" />
</bean>
</property>
</bean>
</beans>
This inner bean also supported in constructor injection as following :
內(nèi)部bean也支持構(gòu)造注入
<?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">
<bean id="CustomerBean" class="com.mkyong.common.Customer">
<constructor-arg>
<bean class="com.mkyong.common.Person">
<property name="name" value="mkyong" />
<property name="address" value="address1" />
<property name="age" value="28" />
</bean>
</constructor-arg>
</bean>
</beans>
<h5 id='beans-collection-elements'>集合</h5>
<list/>
,<set/>
,<map/>
,<props/>
元素纽窟,用來設(shè)置Java Collection
屬性和參數(shù),分別對應(yīng)List
,Set
,Map
,Properties
<bean id="moreComplexObject" class="example.ComplexObject">
<!--調(diào)用setAdminEmails(java.util.Properties) -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- 調(diào)用setSomeList(java.util.List) -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- 代用setSomeMap(java.util.Map) -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- 調(diào)用 setSomeSet(java.util.Set) -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
map.key兼吓,map.value臂港,或者set.value,以可以是以下元素
bean | ref | idref | list | set | map | props | value | null
<h5 id="beans-collection-elements-merging">集合合并</h5>
集合合并
Spring容器也支持集合合并视搏。應(yīng)用開發(fā)者可以定義父集合<list/>
,<map/>
,<set/>
或者<propx/>
元素审孽,該元素可以有子集合<list/>
,<map/>
,<set/>
或者<props/>
元素集成或者重寫父集合中的值。也就是,子集合中的值是合并父子集合后的值浑娜,其中子集合中的值會覆蓋父集合中的值佑力。
這一章節(jié)討論父-子bean機制。不熟悉父子bean定義機制的筋遭,最好是先去補充下然后回來繼續(xù)
下例中展示了集合合并
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.com</prop>
<prop key="support">support@example.com</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- the merge is specified on the child collection definition -->
<props merge="true">
<prop key="sales">sales@example.com</prop>
<prop key="support">support@example.co.uk</prop>
</props>
</property>
</bean>
<beans>
注意搓萧,在bean child
定義中,指定property
adminEmails
的<props/>
元素中merge=true
屬性宛畦。當(dāng)child
bean被容器解析并且實例化時瘸洛,實例有一個adminEmails
的Properties
集合,該集合包含了父子容器中adminEmails
集合合并后的值次和。
administrator=administrator@example.com
sales=sales@example.com
support=support@example.co.uk
子Properties
集合的將繼承所有父集合中<props/>
定義的值反肋,并且重名屬性值會覆蓋父集合中的值.
這個合并行為,同樣可以用在<list/>
,<map/>
,<set/>
類型上踏施。對于<list/>
元素石蔗,spring合并行為與List
類型的合并一樣罕邀,也就是,spring合并行為維持集合有序养距;父集合中的元素索引位置比子集合元素索引位置靠前诉探。對于Map
,Set
,Properties
集合類型,不存在次序。因此棍厌,沒有次序影響Map
,Set
,Properties
肾胯,這涉及到容器內(nèi)部使用的這些類型的所有實現(xiàn)類。
譯注:這里沒有提到List會不會發(fā)生覆蓋 ,既然沒提到耘纱,那就是List沒有覆蓋行為敬肚。當(dāng)然了,實踐才是王道束析,動手實驗才能驗證推測艳馒,研讀源碼才能知道原理,下面上干貨
Java代碼
public class CollectionMerge {
private List<String> list;
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
}