Рубрики
Без рубрики

Перезагрузка файлов свойств весной

Изучите несколько подходов к получению значений свойств для перезагрузки в Spring Beans, включая область обновления Spring Cloud.

Автор оригинала: baeldung.

1. Обзор

В этом уроке мы покажем, как перезагрузить свойства в приложении Spring .

2. Свойства чтения весной

У нас есть различные варианты доступа к свойствам весной:

  1. Окружающая среда — Мы можем ввести Environment , а затем использовать Environment#getProperty для чтения данного свойства. Среда содержит различные источники свойств, такие как свойства системы, – D параметры и application.properties (.yml) . Кроме того, дополнительные источники свойств могут быть добавлены в Среду с помощью @PropertySource .
  2. Свойства — Мы можем загрузить файлы свойств в экземпляр Properties , а затем использовать его в бобе, вызвав properties.get(“свойство”).
  3. @Значение — Мы можем ввести определенное свойство в боб с помощью @Value(${‘property’}) аннотации.
  4. @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 .