2012-10-02 57 views
32

我有一個彈簧3.1 @Configuration,需要一個屬性foo來建立一個bean。該物業在defaults.properties中定義,但如果應用程序具有活動的override春季配置文件,則可能會被overrides.properties中的物業覆蓋。Spring配置文件可以選擇@PropertySources嗎?

沒有覆蓋,代碼是這樣的,和工作...

@Configuration 
@PropertySource("classpath:defaults.properties") 
public class MyConfiguration { 

    @Autowired 
    private Environment environment; 

    @Bean 
    public Bean bean() { 
     ... 
     // this.environment.getRequiredProperty("foo"); 
     ... 
    } 
} 

我想一個@PropertySourceclasspath:overrides.properties@Profile("overrides")隊伍。有沒有人有任何想法如何實現這一目標?我考慮過的一些選項是重複的@Configuration,但這會違反DRY或ConfigurableEnvironment的程序化操作,但我不確定environment.getPropertySources.addFirst()調用的去向。

放置在一個XML配置下工作,如果我直接與@Value注入的財產,而不是當我用EnvironmentgetRequiredProperty()方法。

<context:property-placeholder ignore-unresolvable="true" location="classpath:defaults.properties"/> 

<beans profile="overrides"> 
    <context:property-placeholder ignore-unresolvable="true" order="0" 
            location="classpath:overrides.properties"/> 
</beans> 

更新

如果你想做到這一點,現在,看看春天啓動的YAML support,尤其是「使用YAML而不是屬性」一節。那裏的配置文件支持會使這個問題沒有實際意義,但目前還沒有@PropertySource的支持。

回答

39

在靜態內部類中添加覆蓋@PropertySource。不幸的是,您必須一起指定所有屬性來源,這意味着創建一個「默認」配置文件作爲「替代」的替代方案。

@Configuration 
public class MyConfiguration 
{ 
    @Configuration 
    @Profile("default") 
    @PropertySource("classpath:defaults.properties") 
    static class Defaults 
    { } 

    @Configuration 
    @Profile("override") 
    @PropertySource({"classpath:defaults.properties", "classpath:overrides.properties"}) 
    static class Overrides 
    { 
     // nothing needed here if you are only overriding property values 
    } 

    @Autowired 
    private Environment environment; 

    @Bean 
    public Bean bean() { 
     ... 
     // this.environment.getRequiredProperty("foo"); 
     ... 
    } 
} 
+2

無法理解爲什麼這個答案有很多upvotes。對配置文件名稱進行硬編碼是違反配置文件的。是不是有類似的方式讓我們通過'spring.profiles.active'參數指定配置文件? – jjoller

2

我想不出比任何其它方式,您建議艾默生,這是在一個單獨的@Configuration文件與@Profile註釋來定義這個bean:

@Configuration 
@Profile("override") 
@PropertySource("classpath:override.properties") 
public class OverriddenConfig { 

    @Autowired 
    private Environment environment; 

    @Bean 
    public Bean bean() { 
     //if.. 
    } 
} 
7

你可以這樣做:

<context:property-placeholder location="classpath:${spring.profiles.active}.properties" /> 

編輯:如果您需要更先進的東西,您可以在應用程序啓動時註冊您的PropertySources。

的web.xml

<context-param> 
    <param-name>contextInitializerClasses</param-name> 
    <param-value>com.xxx.core.spring.properties.PropertySourcesApplicationContextInitializer</param-value> 
    </context-param> 

文件創建:

public class PropertySourcesApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { 

    private static final Logger LOGGER = LoggerFactory.getLogger(PropertySourcesApplicationContextInitializer.class); 

    @Override 
    public void initialize(ConfigurableApplicationContext applicationContext) { 
    LOGGER.info("Adding some additional property sources"); 
    String[] profiles = applicationContext.getEnvironment().getActiveProfiles() 
    // ... Add property sources according to selected spring profile 
    // (note there already are some property sources registered, system properties etc) 
    applicationContext.getEnvironment().getPropertySources().addLast(myPropertySource); 
    } 

} 

一旦你做到了,你只需要在您的上下文中添加:

<context:property-placeholder/> 

我可以」 t真的回答你關於多個配置文件的問題,但我想你可以在這樣的初始化器上激活它們,並且可以註冊approp在配置文件激活期間激活PropertySource項目。

+1

這不是假設只有一個配置文件是活動的嗎? –

+2

您可以使用'applicationContext.getEnvironment()'作爲一個數組訪問已分析的活動配置文件列表。getActiveProfiles()' –

+0

沒錯,您可以同時執行這兩個操作。當時我不知道我們可以傳遞多個配置文件;) –

2

說明:此答案提供了使用@PropertySource屬性文件的替代解決方案。我走了這條路線,因爲它試圖處理多個屬性文件,這些文件可能每個都會覆蓋,同時避免重複代碼,這太麻煩了。

爲每個相關屬性集創建一個POJO接口來定義它們的名稱和類型。

public interface DataSourceProperties 
{ 
    String driverClassName(); 
    String url(); 
    String user(); 
    String password(); 
} 

實現返回默認值。

public class DefaultDataSourceProperties implements DataSourceProperties 
{ 
    public String driverClassName() { return "com.mysql.jdbc.Driver"; } 
    ... 
} 

每個配置文件(例如開發,生產)的子類並覆蓋任何不同於默認值的值。這需要一組互斥的配置文件,但您可以輕鬆添加「默認」作爲「覆蓋」的替代方案。

@Profile("production") 
@Configuration 
public class ProductionDataSourceProperties extends DefaultDataSourceProperties 
{ 
    // nothing to override as defaults are for production 
} 

@Profile("development") 
@Configuration 
public class DevelopmentDataSourceProperties extends DefaultDataSourceProperties 
{ 
    public String user() { return "dev"; } 
    public String password() { return "dev"; } 
} 

最後,自動裝配的屬性配置到需要它們的其他配置。這裏的優點是您不會重複任何@Bean創建代碼。

@Configuration 
public class DataSourceConfig 
{ 
    @Autowired 
    private DataSourceProperties properties; 

    @Bean 
    public DataSource dataSource() { 
     BoneCPDataSource source = new BoneCPDataSource(); 
     source.setJdbcUrl(properties.url()); 
     ... 
     return source; 
    } 
} 

我仍然不相信我會用這根棍子在手動配置屬性文件基於在servlet上下文初始化活動概況。我的想法是,手動配置不適合單元測試,但我現在不太確定。我更喜歡將屬性文件讀到屬性訪問器列表中。

+0

有關屬性和'@ PropertySource'的主要特性是您可以通過多種方式覆蓋它 - 例如使用環境變量或應用程序開關 – Raniz

相關問題