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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="parent" class="com.example.spring.bean.collection.CollectionMerge">
<property name="list">
<list >
<value>1</value>
<value>2</value>
</list>
</property>
</bean>
<bean id="child" parent="parent" >
<property name="list">
<list merge="true">
<value>1</value>
<value>2</value>
</list>
</property>
</bean>
</beans>
測試代碼
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class MapMergeTests {
@Autowired
@Qualifier("child")
private CollectionMerge service;
@Test
public void testSimpleProperties() throws Exception {
assertEquals(4, service.getList().size());
}
}
經(jīng)過動手實驗兜看,證明Spring合并對于List類型,并無覆蓋摘投。接下來扣典,我們看看其源碼實現(xiàn)
MutablePropertyValues.mergeIfRequired()方法
private PropertyValue mergeIfRequired(PropertyValue newPv, PropertyValue currentPv) {
Object value = newPv.getValue();
//屬性值是否可合并類
if (value instanceof Mergeable) {
Mergeable mergeable = (Mergeable) value;
//屬性值是否設(shè)置了merge=true
if (mergeable.isMergeEnabled()) {
//合并當(dāng)前屬性
Object merged = mergeable.merge(currentPv.getValue());
return new PropertyValue(newPv.getName(), merged);
}
}
return newPv;
}
上面代碼中Mergeable
接口共有5個實現(xiàn)類ManagedList
,ManagedArray
,ManagedMap
,ManagedSet
,ManagedProperties
ManagedList.merge(Object parent)方法
public List<E> merge(Object parent) {
//防御性拋異常
if (!this.mergeEnabled) {
throw new IllegalStateException("Not allowed to merge when the 'mergeEnabled' property is set to 'false'");
}
if (parent == null) {
return this;
}
//不能合并非List類型集合
if (!(parent instanceof List)) {
throw new IllegalArgumentException("Cannot merge with object of type [" + parent.getClass() + "]");
}
List<E> merged = new ManagedList<E>();
//注意順序监婶,先增加父bean中的value值旅赢,所以文檔中說父集合元素索引位置靠前
merged.addAll((List) parent);
merged.addAll(this);
return merged;
}
譯注:我勒個去齿桃,為了找這段代碼,灑家差點累吐血煮盼。由此可見短纵,譯者是非常用心的用生命去翻譯文檔。
合并限制
不能合并不同類型的集合僵控,比如合并Map
和List
(譯注:上面的源碼中有這樣的代碼香到,不知聰明的小讀者是否注意到了)。如果你非得這么干报破,那么就會拋出個異常悠就。merge
屬性必須指定給父-子繼承結(jié)構(gòu)bean中的子bean,如果指定給了父集合則無效充易,不會產(chǎn)生預(yù)期的合并結(jié)果梗脾。
強類型集合
Java5中出現(xiàn)了范型,所以可以給集合使用強類型限制盹靴。比如說炸茧,聲明一個只含有String
類型的Collection
。若使用Spring 注入一個強類型Collection
給一個bean稿静,那么就可以利用Spring的類型轉(zhuǎn)換特性 梭冠,該特性能將給定的值轉(zhuǎn)換成合適的類型值,然后賦值給你的強類型Collection
改备。
public class Foo {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
看控漠,飛碟
<beans>
<bean id="foo" class="x.y.Foo">
<property name="accounts">
<map>
<entry key="one" value="9.99"/>
<entry key="two" value="2.75"/>
<entry key="six" value="3.99"/>
</map>
</property>
</bean>
</beans>
在foo
bean的accounts
屬性注入前,強類型集合Map<String,Float>
的泛型信息通過反射獲取悬钳。因此Spring的類型轉(zhuǎn)換機(jī)制識別出元素的value類型將會轉(zhuǎn)換為Float
盐捷,9.99,2.75,3.99
將會轉(zhuǎn)換成Float
類型。
<h5 id=beans-null-element
>Null值和空字串</h5>
Spring treats empty arguments for properties and the like as empty Strings. The following XML-based configuration metadata snippet sets the email property to the empty String value ("").
Spring對于屬性的空參數(shù)轉(zhuǎn)換為空字串默勾。下面的XML片段毙驯,設(shè)置值email屬性為空格字串("")
<bean class="ExampleBean">
<property name="email" value=""/>
</bean>
上面的xml配置相當(dāng)于這樣的java代碼
exampleBean.setEmail("")
<null/>
元素處理null值:
<bean class="ExampleBean">
<property name="email">
<null/>
</property>
</bean>
上面配置相當(dāng)于
exampleBean.setEmail(null)
<h5 id='beans-p-namespace'>XML簡寫p命名空間</h5>
p-命名空間能讓你使用bean
元素屬性替代內(nèi)嵌property/>
元素,用來描述屬性值或者協(xié)作類灾测。
Spirng支持命名空間擴(kuò)展配置,命名空間基于XML Schema定義。本章討論的beans
配置格式定義在XML Schema文檔中垦巴。然而媳搪,p命名空間并不是在XSD文件中,而是存在于Spring核心中骤宣。
下面XML片段解釋了:1使用了標(biāo)準(zhǔn)XML秦爆,第2個使用p-命名空間
<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 name="classic" class="com.example.ExampleBean">
<property name="email" value="foo@bar.com"/>
</bean>
<bean name="p-namespace" class="com.example.ExampleBean"
p:email="foo@bar.com"/>
</beans>
上例中解釋了,在bean定義中使用p-namespace設(shè)置email
屬性憔披。它告訴Spring這里有一個property
聲明等限。前面提到過爸吮,p-namespace 并不存在schema定義,所以p
可以修改為其他名字望门。
譯注,干活都是譯者自己撰寫用于驗證形娇,而非參考手冊原版中的內(nèi)容,之所以驗證,是因為原版E文有看不懂的地方筹误、或者翻譯拿不準(zhǔn)桐早、或者就是閑來無事、或者就是為了湊篇幅厨剪,這些事兒得通過寫代碼驗證搞定了
up fuck goods上干貨
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ppp="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="p-namespace" class="com.example.spring.bean.p.PNamespaceBean"
ppp:email="foo@email.com"/>
</beans>
注意p命名空間的用法xmlns:ppp="http://www.springframework.org/schema/p"
和ppp:email="foo@email.com"
go on fuck goods繼續(xù)干貨
public class PNamespaceBean {
private String email;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
下面樣例中哄酝,2個bean都引用了同一個bean
<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">
<!--傳統(tǒng)-->
<bean name="john-classic" class="com.example.Person">
<property name="name" value="John Doe"/>
<property name="spouse" ref="jane"/>
</bean>
<!--時髦-->
<bean name="john-modern"
class="com.example.Person"
p:name="John Doe"
p:spouse-ref="jane"/>
<!---->
<bean name="jane" class="com.example.Person">
<property name="name" value="Jane Doe"/>
</bean>
</beans>
樣例中2個p-namespace設(shè)置屬性值,出現(xiàn)了一種新的格式聲明引用祷膳。第一個bean中陶衅,使用了<property name="spouse" ref="jane"/>
應(yīng)用bean jane.第二個bean中,使用了p:spouse-ref="jane"
做了相同的好事兒,此時,spouse
是屬性名直晨,然而-ref
表示這不是直接量而是引用另一個bean搀军。
譯注 好事兒,我小時候雖然做好事兒不留名抡秆,但是總能被發(fā)現(xiàn)奕巍,令我非常苦惱儒士。我的媽媽常常揪著我的耳朵問:這又是你干的好事兒吧的止。
<h5 id="beans-c-namespace">c-namespace命名空間</h5>
和p-namespace相似,c-namespace,是Spring3.1中新出的,允許行內(nèi)配置構(gòu)造參數(shù)着撩,而不需使用內(nèi)嵌的constructor-arg
元素
用c
:namespace重構(gòu)構(gòu)造注入
<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"/>
<!-- traditional declaration -->
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
<constructor-arg value="foo@bar.com"/>
</bean>
<!-- c-namespace declaration -->
<bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"/>
</beans>
c:
namespace和p:
使用了相同機(jī)制(ref
后綴表示引用)诅福,通過names設(shè)置構(gòu)造參數(shù)。因為它未定義在XSD schema中(但是存在于Spring內(nèi)核中),所以需要先聲明拖叙。
有一些情況比較特殊氓润,不能識別或者看到構(gòu)造參數(shù)(比如無源碼且編譯時無調(diào)試信息),此時可以求助于參數(shù)索引:
<!-- c-namespace index declaration -->
<bean id="foo" class="x.y.Foo" c:_0-ref="bar" c:_1-ref="baz"/>
由于XML語法薯鳍,索引標(biāo)記需要
_
開頭作為XML屬性名稱,而不能使用數(shù)字開頭(盡管某些ID支持)
在實際中咖气,構(gòu)造注入(name匹配/類型匹配/索引匹配)是非常高效的,一般情況下,推薦使用 name匹配方式配置挖滤。
<h5 id='beans-compound-property-names'>復(fù)合屬性</h5>
在設(shè)置bean屬性時崩溪,可以使用復(fù)合或者內(nèi)嵌屬性,組件路徑可以有多長寫多長,除了最后一個屬性斩松,其他屬性都不能為null
伶唯。看下面的bean定義
<bean id="foo" class="foo.Bar">
<property name="fred.bob.sammy" value="123" />
</bean>
bean foo
有屬性fred
,fred
有屬性bob
,bob
有屬性sammy
,最后的sammy
屬性賦值"123"
惧盹。在beanfoo
構(gòu)造后乳幸,fred
屬性和bob
屬性都不能為null
否則拋異常NullPointerException
<h4 id='beans-factory-dependson'>使用depends-on</h4>
若bean是另個bean的依賴瞪讼,通常是指該bean是另個bean的屬性。在XML中通過<ref/>
元素配置實現(xiàn)粹断。然而符欠,bean之間并不全是直接依賴。舉個栗子,類中有個靜態(tài)初始化需要出發(fā),像注冊數(shù)據(jù)庫驅(qū)動這樣的姿染。depends-on
屬性能強制這些先決條件首先完成執(zhí)行初始化背亥,然后再去使用它(比如用于注入)。
下面的樣例中悬赏,展示了使用depends-on
來表達(dá)bean之間的依賴關(guān)系:
<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
也可以依賴多個bean狡汉,為depends-on
屬性值提供一個bean name列表,用逗號闽颇,空白盾戴,分號分隔。
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
在單例bean中兵多,
depends-on
屬性既可以設(shè)定依賴的初始化時機(jī)尖啡,也可以相應(yīng)的設(shè)定依賴的銷毀時機(jī)。在bean被銷毀之前,bean使用depdnds-on
屬性定義的依賴bean會首先被銷毀剩膘。因此depends-on
也能控制銷毀順序衅斩。
<h4 id='beans-factory-lazy-init'>延遲初始化</h4>
ApplicationContext
的各種實現(xiàn)默認(rèn)的初始化處理過程,都是盡早的創(chuàng)建怠褐、配置所有的單例bean畏梆。通常,這種預(yù)先實例化是非常好的奈懒,因為在配置的錯誤或者環(huán)境問題立刻就能暴露出來奠涌,而不是數(shù)小時甚至數(shù)天后才發(fā)現(xiàn)。若不需要此行為磷杏,可以通過設(shè)置lazy-initialized
延遲加載來阻止預(yù)先初始化溜畅。lazy-initialized
bean告訴Ioc容器,只有在第一次請求的時候采取初始化极祸,而不是在啟動容器時初始化慈格。
在XML中,屬性lazy-init
控制<bean/>
元素的初始化遥金。
<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.foo.AnotherBean"/>
ApplicationContext
解析上面的配置峦椰,在啟動時,不會預(yù)先初始化這個標(biāo)記為lazy的bean汰规,為標(biāo)記lazy的bean則會立刻初始化。
如果一個非延遲的單例bean依賴了lazy延遲bean物邑,ApplicationContext
會在啟動時就創(chuàng)建lazy延遲bean,因為它必須滿足單例bean依賴溜哮。延遲bean注入給單例bean滔金,就意味著,它不會延遲加載的茂嗓。
通過設(shè)置<beans/>
元素的default-lazy-init
屬性餐茵,可以設(shè)置容器級別的延遲加載∈鑫看樣例:
<beans default-lazy-init="true">
<!-- no beans will be pre-instantiated... -->
</beans>
<h4 id='beans-factory-autowire'>自動裝配</h4>
Spring容器提供自動裝配忿族,用于組織bean之間的依賴◎蛎可以讓Spring道批,通過檢查ApplicationContext
內(nèi)容完成自動注入。自動裝配有以下優(yōu)點:
- 自動裝配能明顯減少屬性和構(gòu)造參數(shù)的配置入撒。(在這方面隆豹,還有其他的機(jī)制也能達(dá)到此目的,比如bean 模板,在后面的章節(jié)里有詳細(xì)的講解)
- 自動裝配可擴(kuò)展性非常好茅逮。比如璃赡,給類增加了依賴,無需修改配置,依賴類就能自動注入。因此献雅,自動裝配在開發(fā)期非常有用碉考,在代碼不穩(wěn)定時,無需修改編碼即可完成切換挺身。
在XML中侯谁,設(shè)置<bean/>
元素的autowire
屬性來設(shè)定bean的自動裝配模式。自動裝配有5種模式瞒渠×颊簦可以選擇任意一種,來設(shè)置bean的裝配模式伍玖。(譯注嫩痰,這不是廢話么,有5中模式窍箍,每種都能隨便用串纺,假設(shè)有一種不能用,那就是4種模式了么)
Table 5.2. 自動裝配模式
模式 | 解釋 |
---|---|
no | (默認(rèn)的)非自動裝配椰棘。必須使用ref 元素定義bean引用纺棺。對于大規(guī)模系統(tǒng),推薦使用邪狞,明確的指定依賴易于控制祷蝌,清楚明了。它在某種程度上說明了系統(tǒng)的結(jié)構(gòu)帆卓。 |
byName | 通過屬性名稱property name自動裝配巨朦。Spring會查找與需要自動裝配的屬性同名bean米丘。舉個栗子,若在bean定義中設(shè)置了by name方式的自動裝配糊啡,該bean有屬性master (當(dāng)然了拄查,還得有個setMaster(..)寫屬性方法),Spring會查找一個名叫master 的bean,并將它注入給master 熟悉棚蓄。 |
byType | 若在容器中存在一個bean堕扶,且bean類型與設(shè)置自動裝配bean的屬性相同,那么將bean注入給屬性梭依。若與屬性同類型的bean多于1個稍算,則會拋出我們期待已久的致命異常,也就意味著這個bean也許不適合自動注入睛挚。若不存在匹配的bean邪蛔,啥都不會發(fā)生;屬性也不會設(shè)置,然后就沒有然后了扎狱。 |
constructor | Analogous to byType, but applies to constructor arguments. If there is not exactly one bean of the constructor argument type in the container, a fatal error is raised.和byType模式類似侧到,但是應(yīng)用于構(gòu)造參數(shù)。若在容器中不存在與構(gòu)造參數(shù)類型相同的bean淤击,那么接下來呢匠抗,拋異常唄,還能干啥? |
byType或者constructor自動裝配模式,可以裝配arrays數(shù)組和范型集合污抬。 這種個情況
下汞贸,容器內(nèi)匹配類型的bean才會注入給依賴。若key類型是String
,你也能自動裝配強類型Maps
印机。一個自動裝配的Map矢腻,所有 匹配value類型的bean都會注入Map.value
,此時射赛,Map的key就是相應(yīng)的bean的name多柑。
可以結(jié)合自動裝配和依賴檢查,依賴檢查會在裝配完成后執(zhí)行楣责。
<h5 id='beans-autowired-exceptions'>自動裝配的局限和缺點</h5>
自動裝配最好是貫穿整個項目竣灌。若不是全部或大部分使用自動裝配,而僅僅自動裝配一兩個bean定義秆麸,可能會把開發(fā)者搞暈初嘹。(譯注,最可能的原因是沮趣,開發(fā)者對自動裝配機(jī)制不熟悉屯烦,或者想不到項目中居然還使用了自動裝配模式,當(dāng)發(fā)生問題時,擦的漫贞,找都沒地方找去甸箱,調(diào)試信息里只能看到經(jīng)過橫切織入事務(wù)代理的proxy)
總結(jié)局限和缺點:
- 屬性中和構(gòu)造參數(shù)明確的依賴設(shè)置會覆蓋自動裝配。不能自動裝配所謂的簡單屬性迅脐,比如原始類型,
Strings
和Classes
(簡單屬性數(shù)組)豪嗽。這是源于Spring的設(shè)計谴蔑。 - 和明確裝配相比,自動裝配是不確切的龟梦。正如上面的列表中提到的隐锭,Spring謹(jǐn)慎避免匹配模糊,若真的匹配不正確计贰,則導(dǎo)致錯誤發(fā)生钦睡,Spring 管理的對象之間的關(guān)系記錄也變的不明確了。
- 對于根據(jù)Spring容器生成文檔的工具躁倒,裝配信息將變的無用荞怒。
- 容器內(nèi)多個bean定義可能會匹配設(shè)置為自動裝配的
setter
方法或者構(gòu)造參數(shù)的類型。對于arrays秧秉,collections,或者maps,這不是個問題褐桌。然而對于期望單一值的依賴,這種歧義將不能隨意的解決象迎。如果發(fā)現(xiàn)多個類型匹配荧嵌,將會拋出異常 .
在后面的場景中,給你幾條建議:
- 放棄自動裝配砾淌,使用明確裝配
- 避免通過在bean定義中設(shè)置
autowire-candidate
屬性為false的方式來設(shè)置自動裝配啦撮,下一章節(jié)會講 - 通過設(shè)置
<bean/>
袁術(shù)的primary
屬性為true
來指定單個bean定義作為主候選bean。 - 使用基于注解的配置實現(xiàn)更細(xì)粒度的控制汪厨,參看Section 5.9, “Annotation-based container configuration”.
<h5 id='beans-factory-autowire-candidate'>排除自動裝配bean</h5>
在每個bean的設(shè)置中赃春,你可以排除bean用于自動裝配。XML配置中骄崩,設(shè)置<bean/>
元素的autowire-candidate
屬性為false
聘鳞;容器將不使用該bean自動裝配。(包括注解配置,像@Autowired
)
- 使用對bean名字進(jìn)行模式匹配來對自動裝配進(jìn)行限制要拂。其做法是在<beans/>元素的'default-autowire-candidates'屬性中進(jìn)行設(shè)置抠璃。比如,將自動裝配限制在名字以'Repository'結(jié)尾的bean脱惰,那么可以設(shè)置為"Repository“搏嗡。對于多個匹配模式則可以使用逗號進(jìn)行分隔。注意,如果在bean定義中的'autowire-candidate'屬性顯式的設(shè)置為'true' 或 'false'采盒,那么該容器在自動裝配的時候優(yōu)先采用該屬性的設(shè)置旧乞,而模式匹配將不起作用。譯注這一段翻譯是從網(wǎng)上copy過來的磅氨,我勒個擦尺栖,得趕緊睡覺去了*
這些設(shè)置非常有用。但是這些被排除出自動注入的bean是不會自動注入到其他bean烦租,但是它本身是可以被自動注入的延赌。
<h4 id='beans-factory-method-injection'>方法注入</h4>
一般情況,容器中的大部分的bean都是單例的叉橱。當(dāng)單例bean依賴另一個單例bean挫以,或者一個非單例bean依賴另個非單例bean是,通常是將另一個bean定義成其他bean的屬性窃祝。當(dāng)bean的生命周期不同時掐松,那么問題來了。假設(shè)單例bean A依賴非單例bean(prototype) B粪小,也許會在每個方法里都需要B大磺。容器之創(chuàng)建了一個單例bean A,因此只有一次將B注入的機(jī)會糕再。A調(diào)用B量没,需要很多B的實例 ,但是容器不會這么干。
解決辦法是放棄一些IoC控制反轉(zhuǎn)突想。令A(yù)實現(xiàn)接口ApplicationContextAware
殴蹄,此時A能夠感知容器,即獲取ApplicationContext
猾担,每次當(dāng)A調(diào)用B時袭灯,調(diào)用容器的getBean("B")方法用以創(chuàng)建B的實例“筻冢看樣例:
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
并不推薦上面的做法稽荧,因為業(yè)務(wù)代碼耦合了Spring 框架。方法注入,是SpringIoc容器的高級特性工腋,能夠簡潔的滿足此場景姨丈。
想要了解更多的方法注入,參看此博客
<h5 id='beans-factory-lookup-method-injection'>查找式方法注入</h5>
查找式是指擅腰,容器為了覆蓋它所管理的bean的方法蟋恬,在容器范圍內(nèi)查找一個bean作為返回結(jié)果。通常是查找一個原型(prototype)bean趁冈,就像是上面章節(jié)中提到過的場景歼争。Srping框架拜马,使用CGLIB
類庫生成動態(tài)子類的字節(jié)碼技術(shù),覆蓋方法沐绒。
為了能讓動態(tài)子類能運行俩莽,其父類不能是
final
類,被覆蓋的方法也不能是final
。還有乔遮,你得自己測試父類是否含有abstract
方法扮超,如果有,需要你提供默認(rèn)實現(xiàn)蹋肮。最后瞒津,被方法注入的對象不能序列化。Spring 3.2以后括尸,不需要CGLIB
的類路徑了,因為CGLIB
被打包入了org.springframework 包病毡,和Spring-core 這個jar包在一起了濒翻。既是為了方便也是為了避免CGLIB
包與應(yīng)用中用到的CGLIB
包沖突。
來看看前面提到的CommandManager
類的代碼片段啦膜,Spring容器會動態(tài)的覆蓋createCommand()
方法的實現(xiàn)有送。這樣CommandManager
類就不會依賴任何Spring API了。下面是修改過后的
package fiona.apple;
// 不再有 Spring imports!
public abstract class CommandManager {
public Object process(Object commandState) {
// grab a new instance of the appropriate Command interface
//
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
// okay... but where is the implementation of this method?
//okay....但是方法實現(xiàn)在哪里?
protected abstract Command createCommand();
}
在含有被注入方法的類中(像CmmandManager
類)僧家,被注入方法需要使用以下簽名
<public|protected> [abstract] <return-type> theMethodName(no-arguments);
動態(tài)生成子類會實現(xiàn)抽象方法雀摘。若該方法不是抽象的,動態(tài)生成自來則會重寫在源類中的方法八拱。配置如下:
<!-- a stateful bean deployed as a prototype (non-singleton) -->
<bean id="command" class="fiona.apple.AsyncCommand" scope="prototype">
<!-- inject dependencies here as required -->
</bean>
<!-- commandProcessor uses statefulCommandHelper -->
<bean id="commandManager" class="fiona.apple.CommandManager">
<lookup-method name="createCommand" bean="command"/>
</bean>
在commandManager
類調(diào)用createCommand
方法時阵赠,動態(tài)代理類將會被識別為commandManager
返回一個command
bean的實例。將command
bean設(shè)置成prototype
,一定要小心處理肌稻。若被設(shè)置成了singleton
清蚀,每次調(diào)用將返回同一個command
bean。
感興趣的小讀者也找找
ServiceLocatorFactoryBean
類(在org.springframework.beans.factor.config
包)來玩玩爹谭。使用ServiceLocatorFactoryBean
類的處理手法和另一個類ObjectFactoryCreatingFactoryBean
類似枷邪,但是ServiceLocatorFactoryBean
類與虛擬指定你自己的lookup接口(查找接口),這與Spring指定lookup接口略有不同诺凡。詳情參看這些類的javadocs
譯注东揣,今天加班晚了點,到家時23:30了腹泌,可是今天還沒翻嘶卧。進(jìn)了家門,打開電腦真屯,翻一小節(jié)再說脸候,要不估計睡不著覺了。對于我自己的毅力,我還是有相當(dāng)?shù)恼J(rèn)識的运沦,比如:無論咳的多么嚴(yán)重泵额,都能堅持抽煙,由此可見一斑携添。以上是玩笑嫁盲。我的意志力并不強,但是意志薄弱也有意志薄弱的積極的正面的意義烈掠,比如我養(yǎng)成了每天翻點東西的習(xí)慣羞秤,哪怕就是再困、再餓左敌、再累瘾蛋,也得翻譯一下,因為要是不翻譯的話矫限,我就得跟自己的習(xí)慣作斗爭了哺哼,準(zhǔn)確的說是和自己斗爭,而我卻又沒有與自己斗爭的念想叼风,我根本打不過我自己取董,就這樣,我又翻了一小節(jié)
<h5 id="beans-factory-arbitrary-method-replacement">任意方法替換</h5>
還有一種方法注入方式无宿,不如lookup method
注入方式好用茵汰,可以用其他bean方法實現(xiàn)替換受管理的bean的任意方法。你可以跳過本節(jié)孽鸡,當(dāng)真的需要時再回來也是可以的蹂午。
在xml配置中,設(shè)置replaced-method
元素,就可用其他實現(xiàn)來替換已經(jīng)部署的bean中存在的方法實現(xiàn)梭灿』拢考慮下面的類,有一個我們要重寫的方法computeValue
public class MyValueCalculator {
public String computeValue(String input) {
// balbalba
}
// 其他方法...
}