2014-02-21 148 views
2

我有以下設置:Spring配置通屬性引用bean

<bean id="b1" class="SomeClass"> 
    <property name="foo" ref="foo1"/> 
</bean> 

<bean id="b2" class="SomeClass"> 
    <property name="foo" ref="foo2"/> 
</bean> 

<bean id="foo1" class="FooClass"> 
    <constructor-arg index="0"><ref bean="dataSource1"/></constructor-arg> 
    ...other constructor args 
</bean> 

<bean id="foo2" class="FooClass"> 
    <constructor-arg index="0"><ref bean="dataSource2"/></constructor-arg> 
    ...other constructor args 
</bean> 

有沒有一種方法可以讓我避免重複FooClass?我想在bean b1和b2中執行的操作是將引用添加到FooClass中,但是指定數據源的所有其他構造函數參數都是相同的。

感謝

吉姆

+0

另一點,我當時無法使用註釋配置必須是在XML –

回答

0

考慮到你的實現,你可能想要去尋找Bean Definition Inheritance

從春天documentation

一個bean定義可以包含大量的配置信息, 包括構造函數參數,屬性值以及 容器的具體信息,比如初始化方法,靜態 工廠方法名,等等。子bean定義從父定義繼承 配置數據。孩子的定義可以根據需要覆蓋一些值或添加其他值。使用父母和子女的 bean定義可以節省大量的輸入。實際上,這是模板的形式 。

基本上它說的是,你可以有一種「模板爲您的bean定義」標記爲抽象的,並用它在其他兼容豆類繼承這些配置。

這個樣本是從春天documentation採取:

<bean id="inheritedTestBean" abstract="true" 
     class="org.springframework.beans.TestBean"> 
    <property name="name" value="parent"/> 
    <property name="age" value="1"/> 
</bean> 

所以在這一點這個bean不會被實例化,將僅用於bean定義繼承的目的。

<bean id="inheritsWithDifferentClass" 
     class="org.springframework.beans.DerivedTestBean" 
     parent="inheritedTestBean" init-method="initialize"> 

    <property name="name" value="override"/> 
    <!-- the age property value of 1 will be inherited from parent --> 

</bean> 

在這裏,你可以看到,org.springframework.beans.DerivedTestBean用於實例豆,但它會使用父母的所有定義,再加上,它會覆蓋屬性name。該類不需要在父級上指定,但是如果在父級(inheritedTestBean)而不是在子級(inheritsWithDifferentClass)上指定,父級將用於實例化子級。並非一切都被繼承,因爲我們可以在這裏看到:

子bean定義繼承構造器參數值,屬性值 ,並從父類的方法覆蓋,以增加 新值的選項。您指定的任何初始化方法,銷燬方法和/或靜態 工廠方法設置都將覆蓋對應父級設置 。

其餘設置始終取自子定義: 取決於,自動裝配模式,依賴項檢查,單例,範圍,惰性 init。

下面是使用你的類的例子:

<!-- the way you are already using it --> 
<bean id="b1" class="SomeClass"> 
    <property name="foo" ref="foo1"/> 
</bean> 

<!-- if you use it just once, you could declare it inside the bean that uses it -->  
<bean id="b2" class="SomeClass"> 
    <property name="foo"> 
    <bean id="foo1" class="FooClass" parent="foo"> 
     <constructor-arg index="0"><ref bean="dataSource1"/></constructor-arg> 
    </bean> 
    </property> 
</bean> 

<!-- here no class definition, only the default configuration --> 
<bean id="foo" abstract="true"> 
    <!-- constructor arg 0 is defined only on child beans --> 
    <constructor-arg index="1" value="whatever1" /> 
    <constructor-arg index="2" value="whatever2" /> 
    <constructor-arg index="3" value="whatever3" /> 
    <constructor-arg index="4" value="whatever4" /> 
</bean> 

<bean id="foo2" class="FooClass"> 
    <constructor-arg index="0"><ref bean="dataSource2"/></constructor-arg> 
</bean> 
+0

感謝弗朗西斯科,我已經使用了您建議的方法,我認爲這是實現我想要的而不會有太多重複配置的最佳方式。 –

1

如果你希望你的類的一些成員進行動態初始化\居住在每次調用相應的getter,你可以嘗試查找方法注入。閱讀第3.3.4.1頁here

因此,即使包含動態成員的類是在scope = singletone(spring bean容器的默認值)中創建的,每次訪問具有指派的查找方法的字段時,都會根據在查找方法內部實現的業務邏輯。

此外,我在Spring文檔中發現了一個很好的example - 我認爲它非常清楚。看看「3.4.6.1 Lookup方法注入」

+0

感謝您的答覆。我認爲這不會對我的情況有所幫助。從我可以看到的方法注入混合單身人士和原型豆。我所有的bean都是單例,我想要做的就是儘量避免爲同一個類配置幾乎相同的配置,當我需要的是使用不同的數據源時。如果我使用方法注入,我怎麼知道哪個數據源返回? –

1

你在這裏是做什麼的,自動裝配類建設淺析,爲阿維亞德說,你可以使用setter和getter方法爲您的數據源注射

<bean id="foo" class="FooClass"> 
    <constructor-arg index="0">datasource</constructor-arg> 
    ...other constructor args 
</bean> 

    <bean>your datasource bean1</bean> 
    <bean>your datasource bean2</bean> 

在您的實現,您可以設置數據源,如下

@Autowire 
private FooClass foo; 

foo.setDataSource(datasourcebean1); 

你fooClass

public void FooClass(Datasource datasource){ 

     private Datasource datasource; 

     public void setDatSource(Datasource datasource); 

     public Datasource getDataSource(); 
} 

EDIT-按照Spring文檔,如果它的值沒有改變,你可以傳遞構造函數參數。但是對於FooClass來說,你希望在不同的場合傳遞不同的數據源(希望我能正確得到它),所以在這種情況下,你需要在spring初始化時傳遞datasource實例或者datasource1或者datasource2,因爲Spring會期望構造函數參數同時初始化FooClass。稍後在運行時傳遞不同的數據源並使用setter方法設置數據源。

豆Spring配置

<bean id="foo" class="FooClass"> 
     <constructor-arg index="0" ref="datasource1"></constructor-arg> 
     ...other constructor args 
    </bean> 

public class FooClass(){ 
     // on spring initialization, it will inject datasource1 
     public void FooClass(DataSource dataSource){ 
     } 
     have your setter and getter method for datasource 
} 

凡在你的呼叫服務

public class dataBaseInvoke(){ 

public Datasource datasource2 

public FooClass fooClass; 

inside method{ 
    fooClass.setDatasource(datasource2); 
    fooClass.addFoo(); 
} 
} 
+0

我不確定這是如何工作的。在你的例子中,你傳遞給FooClass構造函數的是什麼?我以爲你必須傳遞一個對數據源bean的引用。另外我無法使用@Autowire。 –

0

使用抽象bean

<bean id="foo" class="FooClass"> 
    // Set all properties except datasoure 
    <property name="..." /> 
</bean> 

<bean id="foo1" parent="foo"> 
    <property name="datasource" ref="ds1" /> 
</bean> 
<bean id="foo2" parent="foo"> 
    <property name="datasource" ref="ds2" /> 
</bean> 

當然,你必須使用空的構造器實例化和暴露FooClass性質與存取。如果你不需要foo1foo2在其他地方去內豆。