Spring文檔筆記一(配置、初始化與依賴注入)

Spring文檔筆記一(配置、初始化與依賴注入)

1.1

*配置Spring容器外的對象

可以使用Spring與AspectJ的集成來配置在IoC容器的控制範圍之外創建的對象。請參閱使用AspectJ與Spring依賴注入域對象

實際工作中,我們經常會想new一個Bean,然後在這個Bean中注入Spring管理的其他Bean。但是new出來的bean已經脫離Spring的管控了。

// preConstruction 表示在構造函數前注入
@Configurable(autowire= Autowire.BY_NAME, preConstruction = true)
public class Account { 
    private String name; 
    @Autowired
    private BeanA beanA;  
    /**
    *gets sets
    **/
}

Account accountA=new Account();  //會自動注入beanA
組合多個xml文件
<beans>
        <import resource="services.xml"/>
        <import resource="resources/messageSource.xml"/>
        <import resource="/resources/themeSource.xml"/>

        <bean id="bean1" class="..."/>
        <bean id="bean2" class="..."/>
</beans>

路徑的一點小提示

可以但**不建議使用 ** 相對的“ …/”路徑引用父目錄中的文件。這樣做會創建對當前應用程序外部文件的依賴。特別是,不建議對“ classpath:” URL(例如,“ classpath:…/ services.xml”)URL使用此引用,在URL中,運行時解析過程會選擇“最近的”類路徑根,然後查看其父目錄。類路徑配置的更改可能導致選擇其他錯誤的目錄。

您始終可以使用標準資源位置而不是相對路徑:例如,“ file:C:/config/services.xml”或“ classpath:/config/services.xml”。但是,請注意,您正在將應用程序的配置耦合到特定的絕對位置。通常最好對這樣的絕對位置保留一個間接尋址,例如通過在運行時針對JVM系統屬性解析的“ $ {…}”佔位符。

*1.3Bean的 概述

在容器本身中,這些bean定義表示爲BeanDefinition對象,其中包含(其他信息)以下元數據

  • 全類名:class屬性

  • Bean行爲配置元素 : scope, lifecycle callbacks, 等等

  • ref : 對其他bean的引入 ,也稱爲 依賴 或者 合作

  • 要在新創建的對象中設置的其他配置設置,例如,要在管理連接池的bean中使用的連接數,或池的大小限制

Property Explained in…
class Instantiating beans
name Naming beans
scope Bean scopes
constructor arguments Dependency Injection
properties Dependency Injection
autowiring mode Autowiring collaborators
lazy-initialization mode Lazy-initialized beans
initialization method Initialization callbacks
destruction method Destruction callbacks

ApplicationContext實現還允許註冊在容器外部創建的現有對象

通過**getBeanFactory()**方法訪問ApplicationContext的BeanFactory來完成的,該方法返回BeanFactory實現類DefaultListableBeanFactory,

DefaultListableBeanFactory通過**registerSingleton(…)和registerBeanDefinition(…)**方法支持這種註冊。

但是,典型的應用程序只使用通過元數據bean定義定義的bean。

Bean元數據和手動提供的單例實例需要儘早註冊,以便容器在自動裝配和其他自省步驟中正確地推理它們。雖然在某種程度上支持覆蓋現有元數據和現有單例實例,但未正式支持在運行時(與對工廠的實時訪問同時)對新bean的註冊,並且可能導致bean容器中的併發訪問異常和/或狀態不一致。

😢雖然不是很懂後面一句話說的意思

bean的name

如果不設置name,那麼

  • 第一個字母小寫的駝峯命名法 如 UserService -》 userService
  • 如果前兩個字母都是大寫 則和類名一致 如 USerService -》USerService

bean的別名

在大型系統上可能不同的子系統使用不同的別名便於管理和閱讀
<alias name="subsystemA-dataSource" alias="subsystemB-dataSource"/>
<alias name="subsystemA-dataSource" alias="myApp-dataSource" />
bean的初始化

在XML中會指定class屬性,這個屬性會保存在 BeanDefinition 中 ,有兩個用途:

  • 通過構造函數構造對象 如同new
  • 類中含有靜態工廠方法,用來調用。 方法返回的不一定要是同一個類

如果希望爲靜態內部類配置bean class屬性應該爲 com.example.Foo$Bar Bar是Foo的靜態內部類

構造函數初始化

Spring IoC容器幾乎可以管理您想要它管理的任何類。 它不僅限於管理真正的JavaBean。 大多數Spring用戶更喜歡實際的JavaBean,它們僅具有默認(無參數)構造函數,並具有根據容器中的屬性建模的適當的setter和getter。 您還可以在容器中具有更多奇特的非bean樣式類。 例如,如果您需要使用絕對不符合JavaBean規範的舊式連接池,則Spring也可以對其進行管理。

提供一個空的構造函數 當然也可以用有參構造函數 (需要提供參數)

<bean id="exampleBean" class="examples.ExampleBean"/>

<bean name="anotherExample" class="examples.ExampleBeanTwo"/>

靜態工廠初始化

<bean id="clientService"
        class="examples.ClientService"
        factory-method="createInstance"/>
public class ClientService {
        private static ClientService clientService = new ClientService();
        private ClientService() {}
		//也可以提供參數
        public static ClientService createInstance() {
                return clientService;
        }
}

實例工廠初始化

去掉class屬性,使用factory method 和factory bean

一個實例工廠可以提供多個bean的初始化方法

<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
        <!-- inject any dependencies required by this locator bean -->
</bean>

<!-- the bean to be created via the factory bean -->
<bean id="clientService"
        factory-bean="serviceLocator"
        factory-method="createClientServiceInstance"/>
public class DefaultServiceLocator {

        private static ClientService clientService = new ClientServiceImpl();

        public ClientService createClientServiceInstance() {
                return clientService;
        }
}

在Spring文檔中,factory bean指的是在Spring容器中配置的bean,它將通過實例或靜態工廠方法創建對象。相反,FactoryBean(注意大小寫)指的是特定於spring的FactoryBean。

1.4依賴注入(DI)

依賴項注入(DI)是一個對象定義其依賴項(即與之一起工作的其他對象)的過程 , 只能通過構造函數參數,傳遞參數給工廠方法,在構造完成或工廠方法返回對象實例之後設置對象實例的屬性

當創建bean時容器再將這些依賴對象注入進去。這個過程從根本上顛倒了bean本身通過直接構建類或通過一種機制例如服務定位模式來控制依賴對象的實例化或定位,因此命名爲控制反轉(IoC)

依賴注入,減少了程序耦合。加快了開發效率。 Bean不需要去尋找依賴項,不需要知道依賴項的位置或者類 ,這樣單元測試變得更加簡單。

DI存在兩個主要模式,基於構造函數的依賴注入基於Setter的依賴注入

基於構造函數的依賴注入

構造函數參數會去匹配傳過來的參數類型,當參數不混淆的時候,按照傳參的順序傳入。


public class Foo {

        public Foo(Bar bar, Baz baz) {
                // ...
        }
}

當參數不混淆的時候,不需要傳入參數的位置索引和類型。

<beans>
        <bean id="foo" class="x.y.Foo">
                <constructor-arg ref="bar"/>
                <constructor-arg ref="baz"/>
        </bean>

        <bean id="bar" class="x.y.Bar"/>

        <bean id="baz" class="x.y.Baz"/>
</beans>

當引用另一個bean時,類型是已知的,並且可以發生匹配(與前面的示例一樣)。 當使用簡單類型(例如 true </ value>)時,Spring無法確定值的類型,因此在沒有幫助的情況下無法按類型進行匹配。 考慮以下類別:

public class ExampleBean {

        // Number of years to calculate the Ultimate Answer
        private int years;

        // The Answer to Life, the Universe, and Everything
        private String ultimateAnswer;

        public ExampleBean(int years, String ultimateAnswer) {
                this.years = years;
                this.ultimateAnswer = ultimateAnswer;
        }
}

這時可以註明類型

<bean id="exampleBean" class="examples.ExampleBean">
        <constructor-arg type="int" value="7500000"/>
        <constructor-arg type="java.lang.String" value="42"/>
</bean>

也可使用索引 除了解決多個簡單值的模糊性之外,指定索引還解決了構造函數具有相同類型的兩個參數時的模糊性。注意,索引是基於0的。

<bean id="exampleBean" class="examples.ExampleBean">
        <constructor-arg index="0" value="7500000"/>
        <constructor-arg index="1" value="42"/>
</bean>

還可以使用名稱

<bean id="exampleBean" class="examples.ExampleBean">
        <constructor-arg name="years" value="7500000"/>
        <constructor-arg name="ultimateAnswer" value="42"/>
</bean>

請記住,要開箱即用,必須在啓用調試標誌的情況下編譯代碼,以便Spring可以從構造函數中查找參數名稱。如果您無法使用調試標誌(或不想這樣做)來編譯代碼,則可以使用 @ConstructorProperties JDK註釋顯式命名構造函數參數。然後,樣本類必須如下所示:


public class ExampleBean {

        // Fields omitted

        @ConstructorProperties({"years", "ultimateAnswer"})
        public ExampleBean(int years, String ultimateAnswer) {
                this.years = years;
                this.ultimateAnswer = ultimateAnswer;
        }
}

啓用調試標誌 😩又不懂了可能是自動檢測匹配問題叭

就是 javac -g

javac - Java programming language compiler 找-g

maven的話用這個Apache Maven Compiler Plugin

基於setter的依賴注入

基於設置器的 DI是通過在調用無參數構造函數或無參數static工廠方法以實例化您的bean 之後,在您的bean上調用setter方法來完成的。

*基於構造函數還是Setter?

由於您可以混合使用基於構造函數和基於setter的DI,所以對於強制依賴項使用構造函數,對於可選依賴項使用setter方法或配置方法,這是一個很好的經驗法則。注意,可以使用setter方法上的@Required註釋使屬性成爲必需的依賴項。

首先spring團隊建議使用構造函數依賴注入能保證對象不可變以及保證所有成員變量都注入。

此外,注入構造函數的組件總是以完全初始化的狀態返回給客戶機(調用)代碼。

附帶說明一下,大量的構造函數參數是一種不好的代碼味道,這暗示着類可能有太多的責任,應該對其進行重構,以更好地解決問題的適當分離。

Setter注入應該主要用於可選的依賴項,這些依賴項可以在類中分配合理的默認值。

否則,應該在依賴注入的任何地方檢查成員變量不爲null。

Setter注入的唯一好處就是,在對象創建完成後 能夠再次配置 或者重新注入

因此,通過JMX MBean進行管理是用於setter注入的非常好的的用例。

😄暫時沒用到這個東西先不瞭解

依賴注入過程

容器執行bean依賴項解析,如下所示:

  • 使用ApplicationContext描述所有bean的配置元數據創建和初始化。可以通過XML,Java代碼或註釋指定配置元數據。

  • 對於每個bean,其依賴項都以屬性,構造函數參數或static-factory方法的參數(如果您使用的是常規構造函數)的形式表示。在實際創建 Bean 時,會將這些依賴項提供給Bean 。

  • 每個屬性或構造函數參數都是要設置的值的實際定義,或者是對容器中另一個bean的引用。

  • 每個屬性值 或構造函數參數都從其指定的格式轉換爲該屬性或構造函數參數的實際類型。默認情況下,Spring可以將以字符串格式提供的值轉換爲所有內置類型,如int、long、string、boolean等。

    在創建容器時,Spring容器會驗證每個bean的配置。但是,只有在實際創建 Bean之前,纔會設置Bean屬性本身。創建容器時,將創建具有單例作用域並設置爲預先實例化(默認)的Bean。範圍在Bean範圍中定義。否則,僅在請求時才創建Bean。創建和分配bean的依賴及其依賴的依賴(依此類推)時,創建bean可能會導致創建一個bean圖。 這些依賴項之間的分辨率不匹配可能會顯示得較晚,即在第一次創建受影響的bean時。

*循環依賴

循環依賴

如果主要使用構造函數注入,則可能會創建無法解決的循環依賴方案。

例如:A類通過構造函數注入需要B類的實例,而B類通過構造函數注入需要A類的實例。如果您將A類和B類的bean配置爲相互注入,則Spring IoC容器會在運行時檢測到此循環引用,並拋出 BeanCurrentlyInCreationException

一種可能的解決方案是編輯某些類的源代碼,這些類的源代碼由設置者而不是構造函數來配置。或者,避免構造函數注入,而僅使用setter注入。換句話說,儘管不建議這樣做,但是您可以使用setter注入配置循環依賴項。

默認情況下,容器初始化時就會初始化單例對象,如果單例對象依賴有問題就會報錯。

而如果設置延遲加載,則會在使用的時候報錯。

如果不存在循環依賴,則在注入前會初始化完成依賴bean

<bean id="theTargetBean" class="..."/>

<bean id="theClientBean" class="...">
        <property name="targetName">
            <!--   idref指向的bean在容器部署時會驗證bean是否存在 -->
                <idref bean="theTargetBean"/>
        </property>
</bean>
   <!--  上下寫法等價,不過上面的多一個驗證功能 -->
<bean id="theTargetBean" class="..." />

<bean id="client" class="...">
        <property name="targetName" value="theTargetBean"/>
</bean>
基於靜態工廠注入
<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"/>
public class ExampleBean {

        // a private constructor
        private ExampleBean(...) {
                ...
        }

        //可以不返回和當前類相同的bean
        public static ExampleBean createInstance (
                AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) { 
                ExampleBean eb = new ExampleBean (...);
                // some other operations...
                return eb;
        }
}

ref元素是或定義元素內的最後一個元素。 範圍和驗證取決於您是通過 Beanlocalparent 屬性指定其他對象的ID /名稱

<ref bean="someBean"/>
parent

通過parent屬性指定目標bean將創建對當前容器的父容器中的bean的引用。父屬性的值可以與目標bean的id屬性相同,也可以與目標bean的name屬性中的一個值相同,並且目標bean必須位於當前bean的父容器中。

<!-- in the parent context -->
<bean id="accountService" class="com.foo.SimpleAccountService">
        <!-- insert dependencies as required as here -->
</bean>
<!-- in the child (descendant) context -->
<bean id="accountService" <!-- bean name is the same as the parent bean -->
        class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target">
                <ref parent="accountService"/> <!-- notice how we refer to the parent bean -->
        </property>
        <!-- insert other configuration and dependencies as required here -->
</bean>
集合注入

Spring容器還支持集合的合併。應用程序開發人員可以定義一個父風格,,或元素,並有孩子式的,,或元素繼承和父集合覆蓋值。也就是說,子集合的值是合併父集合和子集合的元素的結果,子集合的元素將覆蓋父集合中指定的值。

注意,在bean定義的merge=true屬性的props元素 上使用了屬性。當容器解析並實例化bean時,結果實例具有一個集合,該集合包含子項的集合與父項的集合合併的結果 。

<beans>
        <bean id="parent" abstract="true" class="example.ComplexObject">
                <property name="adminEmails">
                        <props>
                                <prop key="administrator">[email protected]</prop>
                                <prop key="support">[email protected]</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">[email protected]</prop>
                                <prop key="support">[email protected]</prop>
                        </props>
                </property>
        </bean>
<beans>

元素的特定情況下,與List集合類型關聯的語義(即ordered 值集合的概念)得以保留;父級的值先於子級列表的所有值。

<null/>元素處理null的值。例如:

<bean class="ExampleBean">
        <property name="email">
                <null/>
        </property>
</bean>

上面的配置等效於以下Java代碼:

exampleBean.setEmail(null)
depends-on

如果一個bean是另一個bean的依賴項,則通常意味着將一個bean設置爲另一個bean的屬性。通常,您可以使用基於XML的配置元數據中的<ref/> 元素來完成此操作。但是,有時bean之間的依賴性不太直接。例如,需要觸發類中的靜態初始化器,例如數據庫驅動程序註冊。該depends-on屬性可以在初始化使用此元素的bean之前顯式強制初始化一個或多個bean。以下示例使用該depends-on屬性表示對單個bean的依賴關係:

<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
懶加載bean
<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>

然而,當延遲初始化的bean是未延遲初始化的單例bean的依賴項時,ApplicationContext在啓動時創建延遲初始化的bean,因爲它必須滿足單例的依賴項。延遲初始化的bean被注入到一個沒有延遲初始化的單例bean中。

也可以放在beans中 這樣所有的bean默認懶加載

<beans default-lazy-init="true">
        <!-- no beans will be pre-instantiated... -->
</beans>
Autowiried
  • 自動裝配可以大大減少指定屬性或構造函數參數的需要。(本章其他地方討論的其他機制,如bean模板,在這方面也很有價值。)
  • 隨着對象的發展,自動裝配可以更新配置。 例如,如果您需要向類中添加依賴項,則無需修改配置即可自動滿足該依賴項。
Mode Explanation
no (默認)無自動裝配。 Bean引用必須通過ref元素定義。 對於較大的部署,建議不要更改默認設置,因爲明確指定協作者可以提供更好的控制和清晰度。 在某種程度上,它記錄了系統的結構。
byName 按屬性名稱Autowiried。 Spring尋找與需要自動裝配的屬性同名的bean。 例如,如果一個bean定義被設置爲按名稱自動裝配,並且包含一個master屬性(即,它具有setMaster(…)方法),Spring將查找一個名爲master的bean定義,並使用它來設置 屬性。
byType 如果容器中恰好存在一個屬性類型的bean,則允許自動裝配該屬性。如果存在多個異常,則拋出一個致命異常,這表明您不能爲該bean使用byType自動裝配。如果沒有匹配的bean,則什麼也不會發生;屬性未設置。
constructor 類似於byType,但適用於構造函數參數。如果容器中沒有一個構造函數參數類型的bean,則會引發致命錯誤。

您可以將自動裝配行爲與依賴項檢查相結合,依賴項檢查在自動裝配完成後執行。

當自動裝配在整個工程中一致的使用時其效果最好。如果通常情況下不使用自動裝配,僅在一兩個bean定義中使用自動裝配開發人員可能感到非常困惑。

限制和缺陷

  • propertyconstructor-arg設置中的顯式式依賴項始終覆蓋自動裝配。您無法自動裝配簡單的屬性,例如圖元,StringsClasses(以及此類簡單屬性的數組)。 這種限制是由設計造成的。

  • 自動裝配不如顯式連接精確。儘管如上表所述,Spring謹慎地避免猜測,以免產生可能導致意外結果的歧義,但Spring管理對象之間的關係不再明確地記錄下來。

  • Spring容器中能產生文檔的工具可能得不到配置信息。

  • setter方法或構造函數參數指定的類型進行自動裝配時可能匹配到容器中多個bean的定義。對於數組,集合或Maps而言,這是一個不必要的問題。然而對於只期望一個值的依賴而言,這個歧義性不能任意解決。如果不能獲得唯一的bean定義,會拋出異常。

在後一種情況中,您有幾個選項 :

  • 放棄自動佈線,轉而使用明確的佈線。
  • 通過將其bean的autowire-candidate屬性設置爲false,避免自動裝配bean定義,如下一節所述。
  • 通過將其元素的primary屬性設置爲true,將其中一個bean定義指定爲主要候選對象。
  • 如基於註釋的容器配置中所述,通過基於註釋的配置實現更細粒度的控件。 如3.9小節 “基於註解的容器配置”。

在單個bean的基礎上,你可以排除bean在自動裝配之外。在Spring的XML形式中,設置元素的autowire-candidate特性爲false;容器會使自動裝配基礎框架不能得到指定bean定義(包括註解類型的配置,例如@Autowired)。

你也可以根據bean名稱的匹配模式限制自動裝配的候選目標。頂層的元素可以接收default-autowire-candidates特性中的一個或多個模式。例如,爲了限制自動裝配候選目標匹配任何名字以Repository結尾的bean,可以提供一個*Repository值。爲了提供多種模式,可以定義一個以逗號爲分隔符的列表。bean定義中autowire-candidate特性顯示的值true或false最是優先起作用的,對於這些bean而言,模式匹配規則不起作用。

這些技術對於那些你從不想通過自動裝配方式注入到其它bean中的beans而言是很有用的。這不意味着一個排除的bean它本身不能通過自動裝配進行配置。更確切的說,bean本身不是一個進行其它bean進行自動裝配的候選者。

在大多數應用場景中,容器中的大多數bean是單例的。當一個單例bean需要與另一個單例bean協作時,或一個非單例bean需要與另一個非單例bean協作時,你通常通過定義一個bean作爲另一個bean的一個屬性來處理這個依賴關係。當bean的生命週期不同時問題就出現了。假設一個單例bean A需要使用非單例(標準)bean B時,也許A中的每一個方法調用都要使用bean B。容器僅創建單例bean A一次,因此僅有一次設置屬性的機會。容器不能在每次需要bean B時提供一個bean B的新的實例。

* 查找方法注入 (解決單例對象注入多例對象問題)

Spring的方法注入依賴於CGLIB,需要添加Jar包com.springsource.cn.sf.cglib-2.2.0.jar

查找方法注入是容器的一種覆蓋其管理的beans中的方法的能力,可以返回容器中另一個命名bean查找結果。查找通常會涉及到一個標準bean,如前一小節中講的那樣。Spring框架實現了查找方法注入,它是通過使用CGLIB庫生成的字節碼來動態的產生一個覆蓋這個方法的子類。

  • 爲了使此動態子類起作用, Spring bean容器要進行子類化的類不能是final ,要覆蓋的方法也不能爲final
  • 對具有abstract方法的類進行單元測試需要您自己對該類進行子類化,並提供該abstract方法的存根實現。
  • 組件掃描也需要具體的方法,這需要具體的類別。
  • 一個更關鍵的限制是查找方法不能與工廠方法一起工作,尤其是在配置類中不能與@Bean方法同時起作用,由於那種情況下容器不能控制實例的創建,因此不能在飛速寫入中創建一個運行時產生的子類。
  • 最後,方法注入的目標對象不能被序列化。

查看CommandManager前面的代碼片段中的類,您會看到Spring容器將動態覆蓋該createCommand() 方法的實現。您的CommandManager類將沒有任何Spring依賴項:

package fiona.apple;

// no more 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?
        protected abstract Command createCommand();
}

在包含要注入的方法的客戶端類(CommandManager在本例中爲)中,要注入的方法需要以下形式的簽名:

<public|protected> [abstract] <return-type> theMethodName(no-arguments);

如果方法爲abstract,則動態生成的子類將實現該方法。否則,動態生成的子類將覆蓋原始類中定義的具體方法。例如:

<!-- a stateful bean deployed as a prototype (non-singleton) -->
<bean id="myCommand" 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="myCommand"/>
</bean>

每當需要myCommand bean 的新實例時,標識爲commandManager的bean 就會調用其自己的方法。如果確實需要,您必須小心地將bean 部署爲原型 (prototype)

或者,在基於註釋的組件模型中,您可以通過@Lookup註釋聲明一個查找方法:

public abstract class CommandManager {

        public Object process(Object commandState) {
                MyCommand command = createCommand();
                command.setState(commandState);
                return command.execute();
        }
		//第一種寫法
        @Lookup
        protected abstract MyCommand createCommand();
   		 //第二種寫法
     	@Lookup("myCommand")
        protected abstract Command createCommand();
}

注意,您通常會用一個具體的存根實現來聲明這樣的帶註釋的查找方法,以便使它們與Spring組件掃描規則兼容,其中抽象類在缺省情況下會被忽略。此限制不適用於顯式註冊或顯式導入的bean類。

任意方法替換(解決單例對象注入多例對象問題)

一種比查找方法注入更少使用的形式是用另一種方法實現替換管理的bean中任意方法的能力。用戶可以安全跳過本節剩下的部分,直到這個方法真正需要的時候再看。

在基於XML的配置元數據中,對於一個部署的bean,你可以通過replaced-method元素用另一個方法實現替換現有的方法實現。考慮下面的類,有一個我們想覆蓋的computeValue方法:

public class MyValueCalculator {
 
    public String computeValue(String input) {
        // some real code...
    }
 
    // some other methods...
 
}

實現了org.springframework.beans.factory.support.MethodReplacer接口的類提供了一種新的方法定義。

public class ReplacementComputeValue implements MethodReplacer {
 
    public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
        // get the input value, work with it, and return a computed result
        String input = (String) args[0];
        ...
        return ...;
    }
}

部署最初的類的bean定義和指定的重寫方法如下:

<bean class="x.y.z.MyValueCalculator" id="myValueCalculator">
    <!-- arbitrary method replacement -->
    <replaced-method name="computeValue" replacer="replacementComputeValue">
        String</arg-type>
    </replaced-method>
</bean>
 
<bean class="a.b.c.ReplacementComputeValue" id="replacementComputeValue"></bean>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章