3

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;
    }

譯注:我勒個去齿桃,為了找這段代碼,灑家差點累吐血煮盼。由此可見短纵,譯者是非常用心的用生命去翻譯文檔。

合并限制
不能合并不同類型的集合僵控,比如合并MapList(譯注:上面的源碼中有這樣的代碼香到,不知聰明的小讀者是否注意到了)。如果你非得這么干报破,那么就會拋出個異常悠就。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>

foobean的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-initializedbean告訴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è)置會覆蓋自動裝配。不能自動裝配所謂的簡單屬性迅脐,比如原始類型,StringsClasses(簡單屬性數(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的實例。將commandbean設(shè)置成prototype,一定要小心處理肌稻。若被設(shè)置成了singleton清蚀,每次調(diào)用將返回同一個commandbean。

注意

感興趣的小讀者也找找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
    }

    // 其他方法...

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末堡妒,一起剝皮案震驚了整個濱河市配乱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌皮迟,老刑警劉巖搬泥,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異伏尼,居然都是意外死亡忿檩,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門爆阶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來燥透,“玉大人沙咏,你說我怎么就攤上這事“嗵祝” “怎么了肢藐?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長吱韭。 經(jīng)常有香客問我吆豹,道長,這世上最難降的妖魔是什么理盆? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任痘煤,我火速辦了婚禮,結(jié)果婚禮上猿规,老公的妹妹穿的比我還像新娘衷快。我一直安慰自己,他們只是感情好姨俩,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布烦磁。 她就那樣靜靜地躺著,像睡著了一般哼勇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上呕乎,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天积担,我揣著相機(jī)與錄音,去河邊找鬼猬仁。 笑死帝璧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的湿刽。 我是一名探鬼主播的烁,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼诈闺!你這毒婦竟也來了渴庆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤雅镊,失蹤者是張志新(化名)和其女友劉穎襟雷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仁烹,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡耸弄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了卓缰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片计呈。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡砰诵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出捌显,到底是詐尸還是另有隱情茁彭,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布苇瓣,位于F島的核電站尉间,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏击罪。R本人自食惡果不足惜哲嘲,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望媳禁。 院中可真熱鬧眠副,春花似錦、人聲如沸竣稽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽毫别。三九已至娃弓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間岛宦,已是汗流浹背台丛。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留砾肺,地道東北人挽霉。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像变汪,于是被迫代替她去往敵國和親侠坎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容