13

我正在處理一個Spring應用程序,我意識到我有一個與我管理我的屬性的方式有關的問題。 我使用Spring環境配置文件爲了加載我的屬性,我最近添加了更多的配置文件,使我的屬性文件不可管理正確使用Spring環境配置文件爲了管理PropertySourcesPlaceholderConfigurer和屬性文件集

屬性文件位於src/main/resources/META-INF/props/內的不同文件夾中,其中eah文件夾與不同的Spring環境配置文件匹配。

我現在至少有5個配置文件,這意味着我有5個子文件夾,每個文件夾都包含具有相同名稱的屬性文件,但只有一些鍵的值不同。

下面是它的外觀:

properties file screen capture

這裏是我是如何配置我的PropertyPlaceholders:

@Configuration 
public class PropertyPlaceholderConfiguration { 

    @Profile(Profiles.CLOUD) 
    static class cloudConfiguration { 
     @Bean 
     public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() throws IOException { 
      PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer(); 
      propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(Boolean.TRUE); 
      propertySourcesPlaceholderConfigurer.setLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:META-INF/props/cloud/*.properties")); 
      return propertySourcesPlaceholderConfigurer; 
     } 
    } 

    @Profile(Profiles.DEFAULT) 
    static class defaultConfiguration { 
     @Bean 
     public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() throws IOException { 
      PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer(); 
      propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(Boolean.TRUE); 
      propertySourcesPlaceholderConfigurer.setLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:META-INF/props/default/*.properties")); 
      return propertySourcesPlaceholderConfigurer; 
     } 
    } 

    @Profile(Profiles.TEST) 
    static class testConfiguration { 
     @Bean 
     public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() throws IOException { 
      PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer(); 
      propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(Boolean.TRUE); 
      propertySourcesPlaceholderConfigurer.setLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:META-INF/props/test/*.properties")); 
      return propertySourcesPlaceholderConfigurer; 
     } 
    } 

    @Profile(Profiles.DEV) 
    static class devConfiguration { 
     @Bean 
     public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() throws IOException { 
      PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer(); 
      propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(Boolean.TRUE); 
      propertySourcesPlaceholderConfigurer.setLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:META-INF/props/dev/*.properties")); 
      return propertySourcesPlaceholderConfigurer; 
     } 
    ... 
    } 

綜上所述,我的問題是:

  • 鍵/值對全部複製到5個不同的文件夾中,因爲只有幾個val你是不同的。

因此,我正在尋找一種新的策略來管理不同環境之間的差異。

任何人都可以請幫忙嗎?

回答

1

將公共屬性拖放到單獨的文件中,並指定將特定配置文件特性作爲每個配置文件的輸入。沒有使用基於Java的Spring配置,但這裏是我如何使用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-3.1.xsd"> 

    <beans profile="default"> 
     <bean id="applicationPropertiesPlaceholder" 
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
      <property name="locations"> 
       <list> 
        <value>classpath:profiles/common.profile.properties</value> 
        <value>classpath:profiles/local.profile.properties</value> 
       </list> 
      </property> 
     </bean> 
    </beans> 

    <beans profile="local"> 
     <bean id="applicationPropertiesPlaceholder" 
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
      <property name="locations"> 
       <list> 
        <value>classpath:profiles/common.profile.properties</value> 
        <value>classpath:profiles/local.profile.properties</value> 
       </list> 
      </property> 
     </bean> 
    </beans> 

    <beans profile="trial"> 
     <bean id="applicationPropertiesPlaceholder" 
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
      <property name="locations"> 
       <list> 
        <value>classpath:profiles/common.profile.properties</value> 
        <value>classpath:profiles/trial.profile.properties</value> 
       </list> 
      </property> 
     </bean> 
    </beans> 

    <beans profile="live"> 
     <bean id="applicationPropertiesPlaceholder" 
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
      <property name="locations"> 
       <list> 
        <value>classpath:profiles/common.profile.properties</value> 
        <value>classpath:profiles/live.profile.properties</value> 
       </list> 
      </property> 
     </bean> 
    </beans> 

</beans> 
+0

謝謝艾倫!嗯,唯一的是你的解決方案迫使一個在同一個文件中有不相關的屬性(即common.profile.properties)... – balteo

+0

建議的解決方案的另一個問題是,如果由於某種原因某些時候我需要不同的值對於我需要將其從公共文件中提取出來的屬性之一放入特定於配置文件的文件中。 – balteo

0

我覺得我在這個interesting blog post解決方案的開始迷迷糊糊。

要從文章引述:

謹防特定環境下的性能冗餘。例如,如果解決方案是針對每個環境 (例如「db-test.properties」,「db-dev.properties」等)具有一個屬性文件,則 ,那麼維護這些屬性的 可能有點兒噩夢 - 如果添加了 屬性「foo」,那麼它必須被添加到每個環境(例如DEV,TEST,PROD等)的 屬性文件中。 PropertyOverrideConfigurer適用於消除此 冗餘,在應用程序上下文 本身中設置默認值,但在單獨的文件中重寫值。然而,它很重要,因爲它可以看到 「神奇」到一個毫無戒心的維護開發人員,他看到在上下文文件中指定了一個值 ,但在運行時使用了另一個值 。

這個想法是依靠PropertyOverrideConfigurer和因素的共同屬性。

4

有很多方法可以做到這一點,但我認爲你是在正確的道路上。 重寫的屬性文件獲得通過BeanFactoryPostProcessor的完成,有兩種實現方式,可以幫助你在這種情況下,所以你不必從頭做到這一點:

PropertySourcesPlaceholderConfigurer & PropertyOverrideConfigurer。

這是使用PropertySourcesPlaceholderConfigurer一個例子:

<bean id="someProperties" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer" abstract="true" > 
    <property name="locations"> 
     <list> 
      <value>classpath:database.properties</value> 
      <value>classpath:email.properties</value> 
     </list> 
    </property> 
    <property name="ignoreUnresolvablePlaceholders" value="false"/> 
</bean> 

<bean id="devProperties" parent="someProperties" > 
    <property name="properties" > 
     <props > 
      <prop key="database.username">Database Username used for Development Environment </prop> 
     </props> 
    </property> 
    <property name="localOverride" value="true" /> 
</bean> 

<bean id="testProperties" parent="someProperties" > 
    <property name="properties" > 
     <props > 
      <prop key="database.username">Database Username used for Testing Environment </prop> 
     </props> 
    </property> 
    <property name="localOverride" value="true" /> 
</bean> 

在這個例子加載默認屬性爲將被用作其他豆類模板的豆,而在具體的豆,說TestEnvironmentProperties豆或DevEnvironmentProperties Bean只覆蓋要從默認屬性文件覆蓋的特定屬性。該示例僅顯示如何在不需要創建其他屬性文件的情況下覆蓋特定屬性,從那裏您可以決定如何選擇使用工廠,簡單外觀類或配置文件系統創建哪個bean,以及您喜歡和匹配的任何內容建築。

此外,如果您認爲此選項過於冗長,則可以使用property-placeholder元素。

我建議你這本書:

Getting started with Spring Framework, Second Edition

它只是你在第5章中所需要的例子。我沒有寫它或什麼,我剛剛買了它,我經歷了許多不好的春天書,我喜歡它。

0

更好的做法是將所有屬性文件放在WAR包裝之外。您可以使用JNDI變量將Spring指向可以讀取外部屬性文件的物理路徑。例如:

<jee:jndi-lookup id="externalFileArea" jndi-name="java:comp/env/mgo/externalFileArea" 
        default-value="/opt/external/props" lookup-on-startup="true"/> 

<util:properties id="myConf" location="file:#{externalFileArea}/my-conf.properties"/> 

<!-- And now, to use an entry from this properties import --> 
<bean id="foo" class="foo.bar.com"> 
    <property name="configParam1" value="#{myConf['fooConfig.param1']}" 
</bean> 

如果在Windows上,JNDI條目可能被指定爲/ C/Users/someone。 最後,添加一個名爲/opt/external/props/my-conf.properties的文件,並在其中放置如下條目:fooConfig.param1 = true

清洗,沖洗,重複。更少的工作,更安全,更容易維護。

0

我會建議「普通」屬性不需要在一個公共文件中,而是可以是代碼中的屬性佔位符的默認值。這使得它們可以通過JVM參數(或本地環境)重寫,而不需要在文件中「管理」。您特定於環境的屬性(在特定於環境的文件中)然後僅指示每個環境中必須提供的啓動應用程序的屬性。因此,他們不會在佔位符中使用默認值。