1. Обзор
Начиная с Spring Boot 1.3, мы можем использовать EnvironmentPostProcessor
для настройки среды
приложения до обновления контекста приложения .
В этом руководстве мы рассмотрим, как загрузить и преобразовать пользовательские свойства в среду,
а затем получить доступ к этим свойствам .
2. Весенняя среда
Абстракция Environment
в Spring представляет среду, в которой работает текущее приложение. В то же время он имеет тенденцию к унификации способов доступа к свойствам в различных источниках свойств, таких как файлы свойств, системные свойства JVM, системные переменные среды и параметры контекста сервлета.
Таким образом, в большинстве случаев настройка среды
означает манипулирование различными свойствами до того, как они станут доступными для наших компонентов. Для начала посетите нашу предыдущую статью об управлении свойствами с помощью Spring .
3. Краткий пример
Давайте теперь создадим простое приложение для расчета цен. Он рассчитает цену либо в валовом, либо в нетто-режиме. Переменные системной среды от третьей стороны будут определять, какой режим расчета выбрать.
3.1. Реализация EnvironmentPostProcessor
Для этого реализуем интерфейс EnvironmentPostProcessor .
Мы будем использовать его для чтения нескольких переменных среды:
calculation_mode=GROSS
gross_calculation_tax_rate=0.15
И мы будем использовать постпроцессор, чтобы выставить их в зависимости от приложения, в данном случае с пользовательским префиксом:
com.foreach.environmentpostprocessor.calculation.mode=GROSS
com.foreach.environmentpostprocessor.gross.calculation.tax.rate=0.15
Затем мы можем просто добавить наши новые свойства в Environment
:
@Order(Ordered.LOWEST_PRECEDENCE)
public class PriceCalculationEnvironmentPostProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {
PropertySource<?> system = environment.getPropertySources()
.get(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);
if (!hasOurPriceProperties(system)) {
// error handling code omitted
}
Map<String, Object> prefixed = names.stream()
.collect(Collectors.toMap(this::rename, system::getProperty));
environment.getPropertySources()
.addAfter(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, new MapPropertySource("prefixer", prefixed));
}
}
Давайте посмотрим, что мы здесь сделали. Во- первых, мы попросили среду
предоставить нам PropertySource
для переменных среды. Вызов результирующего system.getProperty
подобен вызову Java System.getenv().get.
Затем, пока эти свойства существуют в среде, мы создадим новую карту с префиксом.
Для краткости мы пропустим содержимое rename
, но ознакомьтесь с примером кода для полной реализации. Результирующая карта имеет те же значения, что и system
, но с префиксными ключами.
Наконец, мы добавим наш новый PropertySource
в среду.
Теперь, если бин запрашивает com.foreach.environmentpostprocessor.calculation.mode
, Environment
сверится с нашей картой.
Обратите внимание, кстати, что Javadoc EnvironmentPostProcessor
рекомендует нам либо реализовать интерфейс Ordered , либо
использовать аннотацию @Order
.
И это, конечно, только один источник свойств .
Spring Boot позволяет нам работать с многочисленными источниками и форматами.
3.2. Регистрация на весенние фабрики
Чтобы вызвать реализацию в процессе начальной загрузки Spring Boot, нам нужно зарегистрировать класс в META-INF/spring.factories
:
org.springframework.boot.env.EnvironmentPostProcessor=
com.foreach.environmentpostprocessor.PriceCalculationEnvironmentPostProcessor
3.3. Доступ к свойствам с помощью аннотации @Value
Давайте использовать их в паре классов. В примере у нас есть интерфейс PriceCalculator
с двумя реализациями: GrossPriceCalculator
и NetPriceCalculator.
В наших реализациях мы можем просто использовать @Value
для получения наших новых свойств:
public class GrossPriceCalculator implements PriceCalculator {
@Value("${com.foreach.environmentpostprocessor.gross.calculation.tax.rate}")
double taxRate;
@Override
public double calculate(double singlePrice, int quantity) {
//calcuation implementation omitted
}
}
Это удобно, так как мы получаем доступ к любым другим свойствам, таким как те, которые мы определили в application.properties.
3.4. Доступ к свойствам в автонастройке Spring Boot
Теперь давайте рассмотрим сложный случай, когда мы обращаемся к предыдущим свойствам в автонастройке Spring Boot.
Мы создадим класс автоконфигурации для чтения этих свойств. Этот класс будет инициализировать и связывать bean-компоненты в контексте приложения в соответствии с различными значениями свойств:
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public class PriceCalculationAutoConfig {
@Bean
@ConditionalOnProperty(name =
"com.foreach.environmentpostprocessor.calculation.mode", havingValue = "NET")
@ConditionalOnMissingBean
public PriceCalculator getNetPriceCalculator() {
return new NetPriceCalculator();
}
@Bean
@ConditionalOnProperty(name =
"com.foreach.environmentpostprocessor.calculation.mode", havingValue = "GROSS")
@ConditionalOnMissingBean
public PriceCalculator getGrossPriceCalculator() {
return new GrossPriceCalculator();
}
}
Подобно реализации EnvironmentPostProcessor
, класс автоконфигурации также должен быть зарегистрирован в META-INF/spring.factories
:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.foreach.environmentpostprocessor.autoconfig.PriceCalculationAutoConfig
Это работает, потому что пользовательские реализации EnvironmentPostProcessor
срабатывают раньше, чем автоконфигурация Spring Boot . Эта комбинация делает автоконфигурацию Spring Boot более мощной.
И, чтобы узнать больше об автонастройке Spring Boot, ознакомьтесь со статьей Custom Auto-Configuration with Spring Boot .
4. Протестируйте пользовательскую реализацию
Теперь пришло время протестировать наш код. Мы можем установить переменные системной среды в Windows, запустив:
set calculation_mode=GROSS
set gross_calculation_tax_rate=0.15
Или в Linux/Unix мы можем вместо этого экспортировать их:
export calculation_mode=GROSS
export gross_calculation_tax_rate=0.15
После этого мы могли бы запустить тест с помощью команды mvn spring-boot:run
:
mvn spring-boot:run
-Dstart-class=com.foreach.environmentpostprocessor.PriceCalculationApplication
-Dspring-boot.run.arguments="100,4"
5. Вывод
Подводя итог, реализация EnvironmentPostProcessor
способна загружать произвольные файлы в различных форматах из разных мест. Кроме того, мы можем выполнить любое преобразование, необходимое для того, чтобы сделать свойства доступными в среде
для последующего использования. Эта свобода, безусловно, полезна, когда мы интегрируем приложение на основе Spring Boot со сторонними конфигурациями.
Исходный код можно найти в репозитории GitHub .