2011-10-28 62 views
1

我的應用程序可以運行在不同的環境中。我需要爲每個環境配置MY數據模型。數據模型是使用Spring bean構建的。Spring是否允許將抽象bean轉換爲非抽象?

我使用Spring 3.0.5,所以我不能有條件地加載資源。 我有這樣的:

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

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

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

<bean id="Factory" ...> 
<propety name="type"><value>${app.type}</value></property> 
<property> 
<map> 
    <entry key="Temlate1" value-ref="Template1"> 
    <entry key="Temlate2" value-ref="Template1"> 
    <entry key="Temlate3" value-ref="Template1"> 

.................. 

房地產豆創建由工廠:

<bean id="real" factory="Factory" factory-method="getInstance" 
<constructor-arg>Factory</..... 
............. 
</bean> 

Java代碼:

class Factory { 
private Map<String, Object> templateBeans; 

Object getInstance(String name) { 
    return templateBeans.get(name); 
........... 

是否有可能以某種方式來聲明抽象模板豆?因爲我有很大的記憶問題。另一種方式是否存在在版本3.1之前在Spring中有條件地實例化不同的bean?只使用EL是很好的,因爲我不能訪問bean的Java代碼,因爲它們來自第三方庫。

+0

如果我理解正確,你有實例化但未使用的Spring bean,並且您認爲這會導致內存問題。是對的嗎?你有沒有明確診斷出那些未使用的singleton模板bean會導致你的記憶問題?還是在黑暗中拍攝? –

+0

這些模板bean包含對另一個模板bean的引用,總共有1000個附加對象。 – user710818

+1

如果每個對象都消耗10 KB的內存,那麼仍然只有10 MB。確保它們在解決問題之前確實會造成真正的問題。 –

回答

5

我還沒有嘗試過,但我相當確定你可以使用bean別名。

首先將所有模板bean聲明爲懶惰,以便它們在啓動時不會被實例化。

<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/> 

然後用豆別名具有可變指向真正的一個:

<alias name="real" alias="${beanForEnvironment}"/> 

見我的答案在這裏如何很好地加載每環境屬性:

property-placeholder location from another property

0

如果可能的話,一個乾淨的解決方案是不使用Factory,但爲不同的環境使用不同的配置文件,它們都定義了相同的「真實」bean,但是具有不同的實現。在運行時,您只需導入正確的版本,例如模板。$ {} app.type .XML。

另一個更醜陋的解決方案是讓你的模板bean lazy-init bean,並確保它們是動態創建的。你不能將它們注入到工廠的地圖中,因爲無論如何都會將它們實例化。您可以存儲一個beanNames的映射,並使您的Factory ApplicationContextAware。然後在getInstance()方法中返回applicationContext.getBean(beanNames.get(...));

更復雜的解決方案是將XML配置與Spring JavaConfig混合,它允許您在bean定義中使用各種邏輯。

+0

在版本3.0.5中,這是不可能的。可能從3.1 – user710818

+0

您是對的,對於第一種解決方案,您需要將變量$ {app.type}替換爲構建類型,例如,由maven配置文件,但這不是你的解決方案,我想。我的第二個解決方案將起作用,但@ pablojim的答案更加優雅。 – greyfairer

1

我以前遇到過這個問題,爲了解決它,我使用了Spring import標籤。例如:

<import resource="file:/location/to/your/config/my_beans.xml"/> 

允許您從應用程序war/jar中外部化Spring XML配置。所以在你的情況下,你將不得不爲每個環境部署一個不同的外部Spring XML配置,但是這也允許你實例化你想要的確切的bean。

+0

我使用變量。 3.1之前Spring中的問題是變量在導入資源後收到值。 – user710818

+1

你的意思是你使用財產所有人? –

0

如果你能夠升級到Spring 3.1,它會給你profies

如果升級不是選項,請查看使用system variables(例如,$ {ENV_SYSTEM:dev})在配置(屬性)之間切換。

另一個好SO的一個是Common strategies when defining Spring beans for different environments

例如有你在service-development.xml發展豆類,導入爲:

<import resource="service-${profile}.xml"/> 

-Dprofile=development啓動它。或者當你捲進QA:-Dprofile=qa

+0

我無法升級到3.1。顯然在3.1中沒有問題。 – user710818

+0

爲什麼你不能使用系統變量:,然後用「-Dprofile = production」啓動它,它只會從「那個」環境? [如果不早於2.5,它就可以工作] – tolitius

0

使用延遲初始化lazy-init="true"但也許豆獲得實例化一次在地圖中引用,所以使用地圖字符串與實例的名稱,以便工廠索要他們的應用程序上下文通過代碼。 context.getBean(MyInterface.class, templates.get(name));

0

正如tolitius建議運行時參數工作得很好。您可以將-Dyourvar = yourvalue傳遞給您的java運行時,並且可以在您的spring導入中使用$ {yourvar}。如果沒有設置,那麼你會收到一個來自spring的未發現資源錯誤。

如果它是一個獨立程序:java YourClass -Dyourvar = yourvalue 當您使用應用程序服務器時,您也可以設置運行時參數。搜索您的服務器文檔,瞭解如何增加服務器內存。您可以設置-Xmx設置的位置通常是您可以設置-Dyourvar不變的地方。