1. Обзор
В этом уроке мы покажем, как перезагрузить свойства в приложении Spring .
2. Свойства чтения весной
У нас есть различные варианты доступа к свойствам весной:
- Окружающая среда — Мы можем ввести Environment , а затем использовать Environment#getProperty для чтения данного свойства. Среда содержит различные источники свойств, такие как свойства системы, – D параметры и application.properties (.yml) . Кроме того, дополнительные источники свойств могут быть добавлены в Среду с помощью @PropertySource .
- Свойства — Мы можем загрузить файлы свойств в экземпляр Properties , а затем использовать его в бобе, вызвав properties.get(“свойство”).
- @Значение — Мы можем ввести определенное свойство в боб с помощью @Value(${‘property’}) аннотации.
- @ConfigurationProperties — мы можем использовать @ConfigurationProperties для загрузки иерархических свойств в боб.
3. Перезагрузка свойств из внешнего файла
Чтобы изменить свойства файла во время выполнения, мы должны поместить этот файл где-то за пределами jar. Затем мы сообщим Spring, где он находится, с помощью параметра командной строки | -spring.config.location=file://{путь к файлу} . Или мы можем поместить его в application.properties.
В свойствах на основе файлов нам нужно будет выбрать способ перезагрузки файла. Например, мы можем разработать конечную точку или планировщик для чтения файла и обновления свойств.
Одной из удобных библиотек для перезагрузки файла является Apache commons-configuration . Мы можем использовать Конфигурацию свойств с другой ReloadingStrategy .
Давайте добавим commons-configuration к вашему pom.xml :
commons-configuration commons-configuration 1.10
Затем мы добавим метод для создания конфигурации Properties bean, который мы будем использовать позже:
@Bean @ConditionalOnProperty(name = "spring.config.location", matchIfMissing = false) public PropertiesConfiguration propertiesConfiguration( @Value("${spring.config.location}") String path) throws Exception { String filePath = new File(path.substring("file:".length())).getCanonicalPath(); PropertiesConfiguration configuration = new PropertiesConfiguration( new File(filePath)); configuration.setReloadingStrategy(new FileChangedReloadingStrategy()); return configuration; }
В приведенном выше коде мы установили FileChangedReloadingStrategy в качестве стратегии перезагрузки с задержкой обновления по умолчанию. Это означает, что Конфигурация свойств проверяет дату изменения файла , если его последняя проверка была до 5000 мс назад .
Мы можем настроить задержку с помощью FileChangedReloadingStrategy#setRefreshDelay.
3.1. Свойства среды перезагрузки
Если мы хотим перезагрузить свойства, загруженные через экземпляр Environment , мы должны расширить источник свойств , а затем использовать PropertiesConfiguration для возврата новых значений из внешнего файла свойств .
Давайте начнем с расширения Источника свойств :
public class ReloadablePropertySource extends PropertySource { PropertiesConfiguration propertiesConfiguration; public ReloadablePropertySource(String name, PropertiesConfiguration propertiesConfiguration) { super(name); this.propertiesConfiguration = propertiesConfiguration; } public ReloadablePropertySource(String name, String path) { super(StringUtils.hasText(name) ? path : name); try { this.propertiesConfiguration = new PropertiesConfiguration(path); this.propertiesConfiguration.setReloadingStrategy(new FileChangedReloadingStrategy()); } catch (Exception e) { throw new PropertiesException(e); } } @Override public Object getProperty(String s) { return propertiesConfiguration.getProperty(s); } }
Мы переопределили метод getProperty , чтобы делегировать его в конфигурацию Properties#getProperty. Следовательно, он будет проверять наличие обновленных значений в интервалах в соответствии с нашей задержкой обновления.
Теперь мы собираемся добавить наш Загружаемый источник свойств в Среду Источники свойств:
@Configuration public class ReloadablePropertySourceConfig { private ConfigurableEnvironment env; public ReloadablePropertySourceConfig(@Autowired ConfigurableEnvironment env) { this.env = env; } @Bean @ConditionalOnProperty(name = "spring.config.location", matchIfMissing = false) public ReloadablePropertySource reloadablePropertySource(PropertiesConfiguration properties) { ReloadablePropertySource ret = new ReloadablePropertySource("dynamic", properties); MutablePropertySources sources = env.getPropertySources(); sources.addFirst(ret); return ret; } }
Мы добавили новый источник свойств в качестве первого элемента , потому что мы хотим, чтобы он переопределял любое существующее свойство с тем же ключом.
Давайте создадим боб для чтения свойства из Среды :
@Component public class EnvironmentConfigBean { private Environment environment; public EnvironmentConfigBean(@Autowired Environment environment) { this.environment = environment; } public String getColor() { return environment.getProperty("application.theme.color"); } }
Если нам нужно добавить другие загружаемые внешние источники свойств, сначала мы должны реализовать наш пользовательский PropertySourceFactory :
public class ReloadablePropertySourceFactory extends DefaultPropertySourceFactory { @Override public PropertySource> createPropertySource(String s, EncodedResource encodedResource) throws IOException { Resource internal = encodedResource.getResource(); if (internal instanceof FileSystemResource) return new ReloadablePropertySource(s, ((FileSystemResource) internal) .getPath()); if (internal instanceof FileUrlResource) return new ReloadablePropertySource(s, ((FileUrlResource) internal) .getURL() .getPath()); return super.createPropertySource(s, encodedResource); } }
Затем мы можем аннотировать класс компонента с помощью @PropertySource :
@PropertySource(value = "file:path-to-config", factory = ReloadablePropertySourceFactory.class)
3.2. Перезагрузка экземпляра Свойств
Среда является лучшим выбором , чем Свойства , особенно когда нам нужно перезагрузить свойства из файла. Однако, если нам это нужно, мы можем расширить java.util.Свойства :
public class ReloadableProperties extends Properties { private PropertiesConfiguration propertiesConfiguration; public ReloadableProperties(PropertiesConfiguration propertiesConfiguration) throws IOException { super.load(new FileReader(propertiesConfiguration.getFile())); this.propertiesConfiguration = propertiesConfiguration; } @Override public String getProperty(String key) { String val = propertiesConfiguration.getString(key); super.setProperty(key, val); return val; } // other overrides }
Мы переопределили getProperty и его перегрузки, а затем делегировали его экземпляру PropertiesConfiguration|/. Теперь мы можем создать компонент этого класса и внедрить его в наши компоненты.
3.3. Перезагрузка боба с помощью @ConfigurationProperties
Чтобы получить тот же эффект с @ConfigurationProperties , нам нужно будет восстановить экземпляр.
Но Spring создаст только новый экземпляр компонентов с прототипом или запросом областью действия.
Таким образом, наш метод перезагрузки среды также будет работать для них, но для синглетов у нас нет выбора, кроме реализации конечной точки для уничтожения и воссоздания компонента или обработки перезагрузки свойства внутри самого компонента.
3.4. Перезагрузка боба со значением @
Аннотация @Value содержит те же ограничения, что и @ConfigurationProperties .
4. Свойства перегрузки по приводу и облаку
Пружинный привод предоставляет различные конечные точки для работоспособности, метрик и конфигураций, но ничего для обновления компонентов. Таким образом, нам нужно Spring Cloud, чтобы добавить в него конечную точку /refresh . Эта конечная точка перезагружает все источники свойств Environment , а затем публикует EnvironmentChangeEvent .
Spring Cloud также представила @RefreshScope , и мы можем использовать его для классов конфигурации или компонентов. В результате область по умолчанию будет refresh вместо singleton .
Используя refresh scope, Spring очистит свой внутренний кэш этих компонентов в EnvironmentChangeEvent . Затем при следующем доступе к бобу создается новый экземпляр.
Давайте начнем с добавления spring-boot-starter-actuator к вашему pom.xml :
org.springframework.boot spring-boot-starter-actuator
Затем давайте также импортируем spring-cloud-зависимости :
org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import Greenwich.SR1
А затем мы добавим spring-cloud-starter :
org.springframework.cloud spring-cloud-starter
Наконец, давайте включим конечную точку обновления:
management.endpoints.web.exposure.include=refresh
Когда мы используем Spring Cloud, мы можем настроить сервер Config для управления свойствами, но мы также можем продолжить работу с нашими внешними файлами. Теперь мы можем обрабатывать два других метода чтения свойств: @Value и @ConfigurationProperties .
4.1. Обновите бобы с помощью @ConfigurationProperties
Давайте покажем, как использовать @ConfigurationProperties с @RefreshScope :
@Component @ConfigurationProperties(prefix = "application.theme") @RefreshScope public class ConfigurationPropertiesRefreshConfigBean { private String color; public void setColor(String color) { this.color = color; } //getter and other stuffs }
Наш боб читает ” цвет” свойство из корня “приложение . тема” свойство . Обратите внимание, что нам действительно нужен метод setter, согласно документации Spring.
После того, как мы изменим значение ” application.theme.color ” в нашем внешнем конфигурационном файле , мы можем вызвать /refresh , чтобы затем мы могли получить новое значение из компонента при следующем доступе.
4.2. Обновить бобы с помощью @Value
Давайте создадим наш образец компонента:
@Component @RefreshScope public class ValueRefreshConfigBean { private String color; public ValueRefreshConfigBean(@Value("${application.theme.color}") String color) { this.color = color; } //put getter here }
Процесс обновления такой же, как и выше.
Однако необходимо отметить, что /обновить не будет работать для бобов с явным синглтон масштаб.
5. Заключение
В этом уроке мы продемонстрировали, как перезагрузить свойства с функциями Spring Cloud или без них. Кроме того, мы показали подводные камни и исключения каждого из методов.
Полный код доступен в нашем проекте GitHub .