Как настроить Spring для частичного и необязательного переопределения свойств?

Я хотел бы иметь настройки свойств, которые могут в определенных средах переопределять определенные свойства. Например, наши свойства JDBC по умолчанию для dev:

  • db.driverClassName = com.mysql.jdbc.Driver
  • db.url = JDBC: MySQL: // локальный: 3306 / ourdb
  • db.username = корень
  • db.password =

Проблема в том, что некоторые из наших разработчиков хотели бы иметь другое имя пользователя / пароль на db или, возможно, даже не локально размещенную db. То же самое можно сказать и о нашей конфигурации rabbitMQ, которая в настоящее время использует аналогичную локальную установку guest / guest. Возможность переопределить свойства определенных элементов этой конфигурации на основе каждого разработчика позволит нам переместить большую часть требований к инфраструктуре / установке для создания программного обеспечения с локальной машины и на выделенные серверы.

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

class Main_PropertyTest { public static void main(String[] args) { String environment = System.getenv("APPLICATION_ENVIRONMENT"); // Environment, for example: "dev" String subEnvironment = System.getenv("APPLICATION_SUB_ENVIRONMENT"); // Developer name, for example: "joe.bloggs" System.setProperty("spring.profiles.active", environment); System.setProperty("spring.profiles.sub", subEnvironment); try(AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PropertyTestConfiguration.class)) { Main_PropertyTest main = context.getBean(Main_PropertyTest.class); main.printProperty(); } } private final String property; public Main_PropertyTest(String property) { this.property = property; } public void printProperty() { System.out.println("And the property is: '" + property + "'."); } } 

И моя конфигурация:

 @Configuration public class PropertyTestConfiguration { @Bean public static PropertySourcesPlaceholderConfigurer primaryPlaceholderConfigurer() { PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer(); propertySourcesPlaceholderConfigurer.setLocation(new ClassPathResource(System.getProperty("spring.profiles.active") + ".main.properties")); return propertySourcesPlaceholderConfigurer; } @Bean public static PropertySourcesPlaceholderConfigurer secondaryPlaceholderConfigurer() { PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer(); propertySourcesPlaceholderConfigurer.setLocation(new ClassPathResource(System.getProperty("spring.profiles.sub") + ".main.properties")); propertySourcesPlaceholderConfigurer.setIgnoreResourceNotFound(true); propertySourcesPlaceholderConfigurer.setIgnoreResourceNotFound(true); propertySourcesPlaceholderConfigurer.setOrder(-1); return propertySourcesPlaceholderConfigurer; } @Bean public Main_PropertyTest main_PropertyTest(@Value("${main.property}") String property) { Main_PropertyTest main_PropertyTest = new Main_PropertyTest(property); return main_PropertyTest; } } 

И для полноты мои dev.main.properties и test.main.properties:

 main.property=dev main.property=test 

Основная проблема заключается в том, что я получаю исключение незаконного аргумента. Насколько я могу судить, то, что я написал, должно быть эквивалентом javaconfig этого метода: http://taidevcouk.wordpress.com/2013/07/04/overriding-a-packaged-spring-application-properties-file- via-an-external-file / К сожалению, я получаю следующую ошибку: java.lang.IllegalArgumentException: Не удалось разрешить placeholder ‘main.property’ в строковом значении $ {main.property}. Обратите внимание, что мне также нужно позаботиться о том, что нет суб-среды, и это тот случай, с которого я начал (хотя я получаю ту же ошибку, даже если оба файла существуют). Если я удалю компонент, который устанавливает второй propertysourcesplaceholderconfigurer, тогда все это работает нормально (под которым я подразумеваю dev.main.properties загружается и «И свойство:« dev ».) Распечатывается).

Вторая проблема заключается в том, что код не выглядит великолепно, и для каждого уровня системы потребуется две настройки PSPC, чтобы они могли получить доступ к этим свойствам. Кроме того, для System.getProperty () требуется много ручных вызовов, поскольку я не мог передать $ {spring.profiles.active} в PSPC.setLocation ();

Примечание. Я попробовал @PropertySources ({primaryproperties, secondaryProperties}), но это не работает, потому что secondaryProperties не существует. Я также пробовал среду @Autowired Environment; и получить свойства от этого, но вторичный PSPC заставляет окружающую среду не быть автоподс …

Поэтому, следуя этому длинному объяснению, мои вопросы:

  • Правильно ли это решение этой проблемы?
  • Если да, то что не так с моей конфигурацией?
  • Как упростить конфигурацию (если вообще)?
  • Есть ли альтернативный механизм, который мог бы решить мою проблему?

Спасибо за ваше время! 🙂

Ваша конфигурация BeanFactoryPostProcessor при настройке BeanFactoryPostProcessor с конфигурацией java, методы должны быть статическими. Однако это может быть еще проще, вместо регистрации вашего собственного PropertySourcesPlaceholderConfigurer использовать поддержку @PropertySource по умолчанию.

Перезапустите конфигурацию jav для следующего

 @Configuration @PropertySource(name="main", value= "${spring.profiles.active}.main.properties") public class PropertyTestConfiguration { @Autowired private Environment env; @PostConstruct public void initialize() { String resource = env.getProperty("spring.profiles.sub") +".main.properties"; Resource props = new ClassPathResource(resource); if (env instanceof ConfigurableEnvironment && props.exists()) { MutablePropertySources sources = ((ConfigurableEnvironment) env).getPropertySources(); sources.addBefore("main", new ResourcePropertySource(props)); } } @Bean public Main_PropertyTest main_PropertyTest(@Value("${main.property}") String property) { Main_PropertyTest main_PropertyTest = new Main_PropertyTest(property); return main_PropertyTest; } } 

Это должно сначала загрузить dev.main.properties и дополнительно test.main.properties которые будут переопределять ранее загруженные свойства (при заполнении курса).

У меня была аналогичная проблема с перезаписью уже существующих свойств в тестах интеграции

Я придумал это решение:

 @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = { SomeProdConfig.class, MyWebTest.TestConfig.class }) @WebIntegrationTest public class MyWebTest { @Configuration public static class TestConfig { @Inject private Environment env; @PostConstruct public void overwriteProperties() throws Exception { final Map systemProperties = ((ConfigurableEnvironment) env) .getSystemProperties(); systemProperties.put("some.prop", "test.value"); } }