2012-10-02 3 views
32

У меня есть весна 3.1 @Configuration, которая нуждается в собственности foo, чтобы построить фасоль. Свойство определено в defaults.properties, но может быть переопределено свойством в overrides.properties, если приложение имеет активный профиль Spring override.Can @PropertySources выбирается по весеннему профилю?

Без переопределения, код будет выглядеть следующим образом, и работа ...

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

    @Autowired 
    private Environment environment; 

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

Я хотел бы @PropertySource для classpath:overrides.properties контингента на @Profile("overrides"). Есть ли у кого-нибудь идеи о том, как это можно достичь? Некоторые варианты, которые я рассмотрел, являются дубликатом @Configuration, но это нарушит DRY или программную манипуляцию с ConfigurableEnvironment, но я не уверен, куда пойдет звонок environment.getPropertySources.addFirst().

Выполнение следующих действий в конфигурации XML работает, если я вставляю свойство напрямую с помощью @Value, но не тогда, когда я использую Environment и метод getRequiredProperty().

<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> 

Update

Если вы пытаетесь сделать это сейчас, проверить Spring ботинка YAML support, в частности, 'Использование YAML вместо Properties' раздел. Поддержка профиля там сделает этот вопрос спорным, но поддержки @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

Не могу понять, почему этот ответ получил так много оборотов. Жестко-кодирование имен профиля относится к точкам профилей. Не существует ли аналогичного способа, позволяющего указать профиль через параметр «spring.profiles.active»? – jjoller

2

Я не могу думать о какой-либо другой путь, чем тот, который вы предложил Эмерсон, который должен определить этот компонент в отдельном файле @Configuration с @Profile аннотацию:

@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 действительно отвечаю на ваш вопрос о нескольких профилях, но я думаю, вы активируете их на таком инициализаторе, и вы можете зарегистрировать соответствующий запрос riate Элементы 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"; } 
    ... 
} 

Подкласс для каждого профиля (например, разработка, производство) и отменяет любые значения, которые отличаются от значений по умолчанию. Для этого требуется набор взаимоисключающих профилей, но вы можете легко добавить «default» в качестве альтернативы «переопределениям».

@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; 
    } 
} 

Я до сих пор не уверен, я буду придерживаться этого более ручной настройки свойств файлов на основе активных профилей в контексте сервлета инициализаторе. Моя мысль заключалась в том, что выполнение ручной настройки не было бы таким же поддающимся модульной проверке, но теперь я не уверен. Я действительно предпочитаю чтение файлов свойств в список аксессуаров свойств.

+0

Основная особенность свойств и '@ PropertySource' заключается в том, что вы можете переопределять ее различными способами - например, с переменными окружения или переключателями приложений – Raniz

Смежные вопросы