1.4.2,依賴性和詳細配置
如上一節所述,您可以將bean屬性和建構式引數定義為對其他托管bean(協作者)的參考或行內定義的值,Spring的基于XML的配置元資料為此目的在其
直值(原語,字串等)
在value所述的屬性
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName" value=https://www.cnblogs.com/dabaieyangzhijidi/p/"com.mysql.jdbc.Driver"/>
前面的XML更簡潔,但是,拼寫錯誤是在運行時而不是設計時發現的,除非您使用IDE(例如IntelliJ IDEA或用于Eclipse的Spring工具)在創建bean定義時支持自動屬性完成,
您還可以配置java.util.Properties實體,如下所示:
<bean id="mappings"
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="properties">
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
</property>
</bean>
Spring容器將
idref元素
所述idref元件是一個防錯方法,主要通過將該容器中的另一個bean的id(將id作為一個字串值傳遞-而不是參考)傳遞給
以下示例顯示了如何使用它:
<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
<property name="targetName">
//此處將 theTargetBean 作為字串傳遞給 theClientBean的targetName屬性
//而不是將theTargetName這個bean的實體傳遞給targetName屬性
<idref bean="theTargetBean"/>
</property>
</bean>
前面的bean定義代碼段(在運行時)與以下代碼段完全等效:
idref 等價的是 value標簽 而不是 ref標簽
<bean id="theTargetBean" class="..." />
<bean id="client" class="...">
<property name="targetName" value=https://www.cnblogs.com/dabaieyangzhijidi/p/"theTargetBean"/>
元素 的local屬性在idref4.0 Bean XSD中不再受支持,因為它不再提供常規bean參考上的值,
升級到4.0模式時,將現有idref local參考更改為idref bean,
idref用法 可以校驗傳入的作為bean的id 會被用來校驗當前id的bean存不存在
<idref></idref>元素常用的位置(至少在spring2.0之前的版本中)是在ProxyFactoryBean bean定義中的AOP攔截器配置中,
在指定攔截器名稱時使用<idref></idref>元素可以防止拼寫錯誤,
ref 對其他Bean的參考
ref元素是
通過標記的bean屬性指定目標bean是最通用的形式,它允許創建對同一容器或父容器中任何bean的參考,而不管它是否在同一XML檔案中,bean屬性的值可以與目標bean的id屬性相同,或者與目標bean的name屬性中的一個值相同,下面的例子展示了如何使用ref元素:
//someBean 可以是bean的id 也可以是bean的name
<ref bean="someBean"/>
ref元素的local屬性在ref4.0 Bean XSD中不再受支持,
因為它不再提供常規bean參考上的值,升級到4.0模式時,將現有ref local參考更改ref bean為,
集合
、
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">[email protected]</prop>
<prop key="support">[email protected]</prop>
<prop key="development">[email protected]</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value=https://www.cnblogs.com/dabaieyangzhijidi/p/"just some string"/>
just some string
map的key或value,或set的value 也可以是以下任意元素:
bean | ref | idref | list | set | map | props | value | null
集合合并
Spring容器還支持合并集合,應用開發者可以定義一個父元素、、
、、
關于合并的這一節討論父-子bean機制,不熟悉父bean和子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>
注意在子bean定義的adminEmails屬性的元素上使用了merge=true屬性,當容器決議并實體化子bean時,生成的實體具有一個adminEmails屬性集合,該集合包含將子bean的adminEmails集合與父bean的adminEmails集合合并的結果,下面的清單顯示了結果:
[email protected]
[email protected]
[email protected]
子屬性集合的值集繼承父屬性中的所有屬性元素,子屬性支持值的值覆寫父屬性集合中的值,
這種合并行為類似地應用于、和
元素的特定情況下,將維護與串列集合型別(即值的有序集合的概念)相關聯的語意,父元素的值位于所有子元素串列的值之前,對于Map、Set和Properties集合型別,不存在排序,因此,對于位于容器內部使用的關聯映射、集合和屬性實作型別下的集合型別,排序語意不起作用,
集合合并的局限性
您不能合并不同的集合型別(例如Map和List),如果嘗試這樣做,將會拋出例外,
該merge屬性必須在下面的繼承的子集合定義中指定,
merge在父集合定義上指定屬性是多余的,不會導致所需的合并,
強型別集合
隨著Java 5中泛型型別的引入,您可以使用強型別集合,也就是說,可以宣告一個Collection型別,使其僅包含(例如)String元素,如果使用Spring將強型別依賴注入Collection到Bean中,則可以利用Spring的型別轉換支持,以便在將強型別Collection 實體的元素添加到之前將其轉換為適當的型別Collection,以下Java類和bean定義顯示了如何執行此操作:
public class SomeClass {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
<beans>
<bean id="something" class="x.y.SomeClass">
<property name="accounts">
<map>
<entry key="one" value=https://www.cnblogs.com/dabaieyangzhijidi/p/"9.99"/>
當準備注入bean 的accounts屬性時,
可以通過反射獲得something有關強型別的元素型別的泛型資訊Map,
因此,Spring的型別轉換基礎結構將各種值元素識別為type Float,
并將字串值(9.99, 2.75和 3.99)轉換為實際Float型別,
空字串值和空字串值
Spring將屬性之類的空引數視為空字串,以下基于xml的配置元資料片段將email屬性設定為空字串值(""),
<bean class="ExampleBean">
<property name="email" value=https://www.cnblogs.com/dabaieyangzhijidi/p/""/>
前面的示例等效于以下Java代碼:
exampleBean.setEmail("");
該
<bean class="ExampleBean">
<property name="email">
<null/>
</property>
</bean>
前面的配置等效于下面的Java代碼:
exampleBean.setEmail(null);
帶有p-名稱空間的XML快捷方式
p-名稱空間允許您使用bean元素的屬性(而不是嵌套的元素)來描述與之合作的bean的屬性值,或者兩者都使用,
Spring支持帶有名稱空間的可擴展配置格式,名稱空間基于XML模式定義,本章中討論的bean配置格式是在XML模式檔案中定義的,但是,p-名稱空間沒有在XSD檔案中定義,只存在于Spring的核心中,
下面的示例顯示了兩個決議為相同結果的XML片段(第一個使用標準XML格式,第二個使用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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="classic" class="com.example.ExampleBean">
<property name="email" value=https://www.cnblogs.com/dabaieyangzhijidi/p/"[email protected]"/>
該示例顯示了email在bean定義中呼叫的p-namespace中的屬性,這告訴Spring包含一個屬性宣告,如前所述,p名稱空間沒有架構定義,因此可以將屬性名稱設定為屬性名稱,
下一個示例包括另外兩個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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="john-classic" class="com.example.Person">
<property name="name" value=https://www.cnblogs.com/dabaieyangzhijidi/p/"John Doe"/>
這個示例不僅包含一個使用p-名稱空間的屬性值,而且還使用一種特殊格式來宣告屬性參考,第一個bean定義使用來創建一個從bean john到bean jane的參考,第二個bean定義使用p:spouse-ref="jane"作為一個屬性來完成完全相同的作業,在本例中,spouse是屬性名,而-ref部分表明這不是一個直接的值,而是對另一個bean的參考,
p-名稱空間不如標準XML格式靈活,
例如,宣告屬性參考的格式與以Ref結尾的屬性沖突,而標準XML格式不會,
我們建議您仔細選擇您的方法,并與您的團隊成員溝通,
以避免同時生成使用所有三種方法的XML檔案,
The p-namespace is not as flexible as the standard XML format.
For example, the format for declaring property references clashes
with properties that end in Ref,whereas the standard XML format does not.
We recommend that you choose your approach carefully
and communicate this to your team members to avoid producing XML documents
that use all three approaches at the same time.
這段沒看懂,這里測驗了以Ref結尾的屬性也是可以用 p:xxxRef-ref
具有c-namespace的XML快捷方式
與使用p-namespace的XML快捷方式類似,Spring 3.1中引入的c-namespace允許使用行內屬性配置建構式引數,而不是嵌套建構式引數元素,說白了就是p-namespace替換property,c-namespace替換constructor-arg
下面的示例使用c:名稱空間執行與 基于建構式的依賴注入相同的操作:
<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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
<!-- 帶有可選引數名稱的傳統宣告 -->
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value=https://www.cnblogs.com/dabaieyangzhijidi/p/"[email protected]"/>
對于建構式引數名不可用的罕見情況(通常是在編譯位元組碼時沒有除錯資訊的情況下),可以使用回退到引數索引,如下所示:
<bean id="beanOne" class="x.y.ThingOne" c:_0-ref="beanTwo" c:_1-ref="beanThree"
c:_2="[email protected]"/>
復合屬性名稱 一個bean中嵌套另外一個bean 并需要給內部的bean賦值
在設定bean屬性時,可以使用復合或嵌套屬性名,只要路徑的所有組件(最終屬性名除外)都不為空,考慮下面的bean定義:
<bean id="something" class="things.ThingOne">
<property name="fred.bob.sammy" value=https://www.cnblogs.com/dabaieyangzhijidi/p/"123" />
所述something bean具有fred屬性,該屬性具有bob屬性,
bob屬性具有sammy 特性,并且最終sammy屬性被設定為值123,
something bean的fred屬性和fred的bob屬性在構造bean之后一定不能為null,
否則,將會引發NullPointerException,
1.4.3,使用depends-on
如果一個bean是另一個bean的依賴項,則通常意味著將一個bean設定為另一個bean的屬性,通常,您可以使用基于XML的配置元資料中的 元素來完成此操作,
但是,有時bean之間的依賴性不太直接,一個示例是何時需要觸發類中的靜態初始值設定項,例如用于資料庫驅動程式注冊,該depends-on屬性可以在初始化使用此元素的bean之前顯式強制初始化一個或多個bean,以下示例使用該depends-on屬性表示對單個bean的依賴關系:
<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
要表達對多個bean的依賴性,就需要用逗號隔開多個名稱
<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" />
depends-on屬既可以指定初始化時間依賴項,
也可以指定對應的銷毀時間依賴項(僅在單例bean中),被依賴的bean會晚于依賴bean之后銷毀
<bean id="serviceOneRef" name="serviceOneName" class="org.springframework.example.service.ServiceOne"
destroy-method="destroyed"/>
public void destroyed(){
System.out.println("ServiceOne destroy");
}
<bean id="serviceTwo" class="org.springframework.example.service.ServiceTwo"
p:name="asdfasdf" depends-on="serviceOneRef"
destroy-method="destroyed" />
public void destroyed(){
System.out.println("serviceTwo destroy");
}
console:
serviceTwo destroy
ServiceOne destroy
1.4.4,懶加載bean
默認情況下,作為初始化程序的一部分,ApplicationContext實作會急切地創建和配置所有的單例bean,通常,這種預實體化是可取的,因為配置或周圍環境中的錯誤是立即發現的,而不是幾小時甚至幾天后發現的,
當這種行為不合適時,您可以通過將bean定義標記為延遲初始化來防止單例bean的預實體化,延遲初始化的bean告訴IoC容器在第一次請求bean實體時(而不是在啟動時)創建bean實體,
在XML中,這種行為是由
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean"/>
當ApplicationContext使用前面的配置時,
lazy bean不會在ApplicationContext啟動時急切地預實體化,
not.lazy bean則會被急切地預實體化,
然而,當懶加載的bean是非懶加載的單例bean的依賴項時,ApplicationContext在啟動時則會創建懶加載的bean,因為它必須滿足單例的依賴項,
您還可以通過使用
<beans default-lazy-init="true">
<!-- no beans will be pre-instantiated... -->
</beans>
1.4.5,自動裝配
Spring容器可以自動裝配協作bean之間的關系,
自動裝配具有以下優點:
- 自動裝配可以大大減少指定屬性或建構式引數的需要,
- 隨著物件的發展,自動裝配可以更新配置,例如,如果您需要向類中添加一個依賴項,則無需修改配置即可自動滿足該依賴項,因此,自動裝配在開發程序中特別有用,而不必擔心當代碼庫變得更穩定時切換到顯式接線的選擇,
使用基于XML的配置元資料時,可以使用元素的autowire屬性為 bean定義指定自動裝配模式
| 模式 | 解釋 |
|---|---|
| no | (默認)沒有自動裝配,想要參考其他的Bean必須由ref元素定義, 對于較大的部署,不建議更改默認設定, 因為顯式地指定需要參考的bean 可以提供更好的控制和清晰度, 在某種程度上,它記錄了系統的結構, |
| byName | 按屬性名稱自動裝配, Spring尋找與需要自動實作的屬性同名的bean, 例如,如果一個bean定義autowire模式設定為byName, 并且它包含一個master屬性(也就是說,它有一個setMaster(..)方法) ,那么Spring將查找一個名為master的bean定義, 并使用它來設定該屬性, 主要還是根據set方法來確定屬性名,如果你有master屬性, 但是你的set方法是setMyMaster(..), 那么Spring會查找名為 myMaster的bean而不是名為 master的bean |
| byType | 適用于set 方法的入參型別, 如果容器中恰好存在該屬性型別的一個bean,則允許該屬性自動注入, 如果存在多個,就會拋出一個致命例外, 這表明您不能對該bean使用byType自動裝配, 如果沒有匹配的bean,則什么也不會發生(沒有設定屬性), |
| constructor | 類似于byType,但適用于建構式引數, 如果容器中沒有建構式引數型別的確切bean,就會引發致命錯誤, |
使用byType或constructor自動裝配模式,您可以自動注入arrays和collections型別,在這種情況下,將提供容器中與期望型別匹配的所有自動裝配候選,以滿足相關性,
如果接收的map 的key值型別為String,那么你也可以讓Spring自動裝配Map型別的值,并且 Map實體的key值為相應的bean名稱,
@Autowired
private List<CusService> serviceLists;
@Autowired
private Map<String,CusService> cusServiceMap;
自動接線的局限性和缺點
自動裝配在專案中一致使用時作業得最好,如果自動裝配沒有被普遍使用,那么使用它來連接一個或兩個bean定義可能會使部分開發人員感到困惑,
考慮自動裝配的局限性和缺點:
- 屬性和構造引數設定中的顯式依賴關系總是覆寫自動裝配,您不能自動連接簡單屬性,如primitives(boolean,int,long等)、String和classes(以及此類簡單屬性的陣列),這種限制被刻意設計的,
- 自動裝配bean不如顯式指定bean精確,不過,正如前面的表中所指出的,Spring已經盡可能避免產生意外結果,Spring管理的物件之間的關系不再被明確地記錄,
- 對于能從Spring容器生成檔案的工具來說生成連接資訊是不可能的了,
- 自動注入依賴項時如果有多個可以匹配的選項,如果注入型別是陣列、集合或映射實體,這不是問題,但是,對于期望使用單個值的依賴項,這種模糊性不能任意解決,如果沒有可用的唯一bean定義,則拋出例外,
在后一種情況下,您有幾個選項:
- 放棄自動裝配,支持顯式布線,
- 通過將bean定義的autowire-candidate設定為false來避免自動裝配,
- 通過將單個bean定義的
元素的primary設定為true,將其指定為主候選bean定義, - 使用基于注釋的配置實作更細粒度的控制,1.9小節會專門講解注解使用,
1.放棄自動裝配,改成指定bean注入 @Qualifier 或者 xml的ref屬性都可以
2.
<bean id="serviceOne" class="org.springframework.example.service.ServiceOne" />
<bean id="serviceTwo" class="org.springframework.example.service.ServiceTwo" />
兩個bean都繼承同一個介面CusService,如果有自動裝配如下
@Autowired
private CusService service;
則啟動時候會報錯
如果給serviceOne增加屬性autowire-candidate="false"
<bean id="serviceOne" class="org.springframework.example.service.ServiceOne" autowire-candidate="false" />
則所有的自動裝配CusService的介面都會優先裝配serviceTwo
3.情況同2 還可以將serviceTwo 增加primary="true"
<bean id="serviceTwo" class="org.springframework.example.service.ServiceTwo" primary="true" />
從自動裝配中排除Bean
在每個bean的基礎上,您可以從自動裝配中排除一個bean,在Spring的XML格式中,將
autowire-candidate屬性被設計為只影響基于型別的自動裝配,
它不影響按名稱的顯式參考,即使指定的bean沒有標記為自動裝配候選,
也會決議顯式參考,因此,如果名稱匹配,按名稱自動裝配仍然會注入一個bean,
patterns 字串接受一個或多個匹配模式,多個patterns 字串之間可以用逗號隔開, 例如 (Repository,Service,*Dao) 這種組合模式
bean本身的autowire-candidates屬性優于
這些技術對于那些您永遠不希望通過自動裝配被注入到其他bean中的bean非常有用,這并不意味著被排除的bean本身不能使用自動裝配進行配置,相反,該bean本身僅僅是不作為其他bean的自動連接候選物件,
public static final String AUTOWIRE_CANDIDATE_ATTRIBUTE = "autowire-candidate";
//獲取autowire-candidate 這個值默認就是true
String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
//判斷 是不是定義的當前bean是不是 default
if (isDefaultValue(autowireCandidate)) {
//如果是default
//查找當前bean 所在beans的default-autowire-candidates屬性 找到配置的patterns運算式
//如果運算式為空 就不處理setAutowireCandidate屬性值 這樣該屬性依舊是true
String candidatePattern = this.defaults.getAutowireCandidates();
if (candidatePattern != null) {
//運算式不為空 判斷當前beanName 是否在運算式范圍內
//在范圍內就setAutowireCandidate設定為true
//否則設定為false
String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
}
}
else {
//如果autowireCandidate 不是 default 是true 那就設定為true
//是false 那就設定為false
bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
}
1.4.6,方法注入
在大多數應用場景中,容器中的大多數bean是 singletons,
當單例Bean需要與另一個單例Bean協作或非單例Bean需要與另一個非單例Bean協作時,通常可以通過將一個Bean定義為另一個Bean的屬性來處理依賴性,生命周期相同的類互相注入時沒有問題,
當bean的生命周期不同時會出現問題,假設單例bean A需要使用非單例(原型)bean B,也許在A的每個方法呼叫上都使用,容器僅創建一次單例bean A,因此只有一次機會來設定屬性,每次需要一個容器時,容器都無法為bean A提供一個新的bean B實體,
一個解決方案是放棄某些控制反轉,您可以通過實作介面ApplicationContextAware ,并使每次容器 A都需要容器 B 的呼叫來請求(通常是新的)bean B實體,從而使bean A知道容器,以下示例顯示了此方法:ApplicationContextAware.getBean("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;
}
}
前面的內容是不理想的,因為業務代碼知道并耦合到Spring框架,方法注入是Spring IoC容器的一項高級功能,使您可以干凈地處理此用例,
您可以在此博客條目中了解有關方法注入動機的更多資訊,
Lookup Method注入
Lookup Method注入是指容器覆寫容器管理bean上的方法并回傳容器中另一個已命名bean的查找結果的能力,查找通常涉及原型bean,如上一節所述的場景,Spring框架通過使用來自CGLIB庫的位元組碼生成動態生成覆寫該方法的子類來實作這種方法注入,
- 要使這個動態子類作業,Spring bean容器子類的類不能是final,要覆寫的方法也不能是final,
- 單元測驗具有抽象方法的類需要您自己創建類的子類,并提供抽象方法的存根實作,
- 具體的方法對于組件掃描也是必要的,這需要具體的類來拾取,
- 另一個關鍵的限制是,Lookup Method 不能與工廠方法一起作業,特別是與配置類中的@Bean方法一起作業,因為在這種情況下,容器不負責創建實體,因此不能動態地創建運行時生成的子類,
對于CommandManager前面的代碼片段中的類,Spring容器動態地覆寫該createCommand() 方法的實作,該CommandManager班沒有任何Spring的依賴,如下所示:
package fiona.apple;
public abstract class CommandManager {
public Object process(Object commandState) {
// 獲取適當的命令介面的新實體
Command command = createCommand();
// 在(希望是全新的)命令實體上設定狀態
command.setState(commandState);
return command.execute();
}
// 實作類在哪呢???
protected abstract Command createCommand();
}
在包含要注入的方法的客戶端類中(本例為CommandManager),要注入的方法需要以下形式的簽名:
<public|protected> [abstract] <return-type> theMethodName(no-arguments);
如果方法為abstract,則動態生成的子類將實作該方法,否則,動態生成的子類將覆寫原始類中定義的具體方法,考慮以下示例:
<!-- 作為原型部署的有狀態bean(非單例)-->
<bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype">
<!-- inject dependencies here as required -->
</bean>
<!-- commandProcessor使用statefulCommandHelper-->
<bean id="commandManager" class="fiona.apple.CommandManager">
<lookup-method name="createCommand" bean="myCommand"/>
</bean>
標識為commandManager的bean在需要myCommand bean的新實體時呼叫它自己的createCommand()方法,是否要將myCommand bean部署為原型,必須仔細確認自己的需求,如果是單例,則每次都回傳相同的myCommand bean實體,
或者,在基于注釋的組件模型中,您可以通過@Lookup注釋宣告一個查找方法,如下面的示例所示:
public abstract class CommandManager {
public Object process(Object commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup("myCommand")
protected abstract Command createCommand();
}
或者,更慣用的是,您可以依賴于目標bean根據查找方法的宣告的回傳型別來決議:
public abstract class CommandManager {
public Object process(Object commandState) {
MyCommand command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup
protected abstract MyCommand createCommand();
}
請注意,您通常應該使用具體的存根實作來宣告這種帶注釋的查找方法,以便它們與Spring的組件掃描規則兼容,其中抽象類在默認情況下會被忽略,此限制不適用于顯式注冊或顯式匯入的bean類,
訪問范圍不同的目標bean的另一種方法是ObjectFactory/ Provider注入點(https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-scopes-other-injection),
您可能還會發現ServiceLocatorFactoryBean(在 org.springframework.beans.factory.config包裝中)有用,
任意方法替換
方法替換注入的形式是用另一個方法實作替換托管bean中的任意方法的能力,這個十分不常用,您可以跳過本節的其余部分,等到您真正需要此功能再來看,
對于基于xml的配置元資料,您可以使用replaced-method元素將一個已部署bean的現有方法實作替換為另一個方法實作,考慮下面的類,它有一個名為computeValue的方法,我們想要覆寫它:
public class MyValueCalculator {
public String computeValue(String input) {
// some real code...
}
}
實作該org.springframework.beans.factory.support.MethodReplacer 介面的類提供了新的方法定義,如以下示例所示:
/**
*用于覆寫現有的computeValue(String input)
*實作在MyValueCalculator
*/
public class ReplacementComputeValue implements MethodReplacer {
public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
//獲取輸入值,使用它,并回傳計算結果
String input = (String) args[0];
...
return ...;
}
}
用于部署原始類并指定方法覆寫的Bean定義類似于以下示例:
<bean id="myValueCalculator" class="x.y.z.MyValueCalculator">
<replaced-method name="computeValue" replacer="replacementComputeValue">
<arg-type>String</arg-type>
</replaced-method>
</bean>
<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>
您可以在
例如,以下所有都是java.lang.String匹配項 :
java.lang.String
String
Str
因為引數的數量通常足以區分每個可能的選擇,所以通過讓您僅鍵入與引數型別匹配的最短字串,此快捷方式可以節省很多輸入
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/35158.html
標籤:Java
