1. 概要

このチュートリアルでは、Springアプリケーションプロパティをリロードする方法を示します。

2. 春のプロパティの読み取り

Springのプロパティにアクセスするためのさまざまなオプションがあります。

  1. Environment Environment を挿入してから、 Environment#getPropertyを使用して特定のプロパティを読み取ることができます。 Environment には、システムプロパティ、 -D パラメータ、 application.properties(.yml)などのさまざまなプロパティソースが含まれています。 また、 @PropertySource を使用して、Environmentに追加のプロパティソースを追加できます。
  2. Properties —プロパティファイルを Properties インスタンスにロードし、 property.get( “property”)。を呼び出すことでBeanで使用できます。
  3. @Value @Value($ {‘property’})アノテーションを使用してBeanに特定のプロパティを挿入できます。
  4. @ConfigurationProperties @ConfigurationProperties を使用して、Beanに階層プロパティをロードできます。

3. 外部ファイルからのプロパティの再読み込み

実行時にファイルのプロパティを変更するには、そのファイルをjarの外のどこかに配置する必要があります。 次に、コマンドラインパラメーター–spring.config.location = file://{ファイルへのパス}を使用してSpringにその場所を通知します。 または、application.properties。に配置することもできます

ファイルベースのプロパティでは、ファイルをリロードする方法を選択する必要があります。 たとえば、エンドポイントまたはスケジューラを開発して、ファイルを読み取り、プロパティを更新できます。

ファイルをリロードするための便利なライブラリの1つは、Apacheのcommons-configurationです。 PropertiesConfigurationをさまざまなReloadingStrategyで使用できます。

commons-configurationpom.xmlに追加しましょう。

<dependency>
    <groupId>commons-configuration</groupId>
    <artifactId>commons-configuration</artifactId>
    <version>1.10</version>
</dependency>

次に、 PropertiesConfiguration 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 を、デフォルトの更新遅延を使用したリロード戦略として設定しています。 これは、 PropertiesConfiguration が、最後のチェックが5000ms前であった場合、ファイル変更日をチェックすることを意味します。

FileChangedReloadingStrategy#setRefreshDelay。を使用して遅延をカスタマイズできます

3.1. 環境プロパティの再読み込み

環境インスタンスを介してロードされたプロパティをリロードする場合は、 PropertySourceを拡張してから、PropertiesConfigurationを使用して外部プロパティファイルから新しい値を返す必要があります。

PropertySourceの拡張から始めましょう。

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 それを委任する方法 PropertiesConfiguration#getProperty。 したがって、更新遅延に応じた間隔で更新された値をチェックします。

次に、ReloadablePropertySourceEnvironmentのプロパティソースに追加します。

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

同じキーで既存のプロパティをオーバーライドするため、最初のアイテムとして新しいプロパティソースを追加しました

Environmentからプロパティを読み取るBeanを作成しましょう。

@Component
public class EnvironmentConfigBean {

    private Environment environment;

    public EnvironmentConfigBean(@Autowired Environment environment) {
        this.environment = environment;
    }

    public String getColor() {
        return environment.getProperty("application.theme.color");
    }
}

他の再読み込み可能な外部プロパティソースを追加する必要がある場合は、最初にcustom 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. プロパティインスタンスのリロード

Environment は、 Properties よりも適切な選択です。特に、ファイルからプロパティを再ロードする必要がある場合はそうです。 ただし、必要に応じて、java.util.Propertiesを拡張できます。

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インスタンスに委任しました。 これで、このクラスのBeanを作成し、コンポーネントに挿入できます。

3.3. @ConfigurationPropertiesを使用したBeanのリロード

@ConfigurationProperties で同じ効果を得るには、インスタンスを再構築する必要があります。

ただし、Springは、プロトタイプまたはリクエストスコープを持つコンポーネントの新しいインスタンスのみを作成します。

したがって、環境をリロードする手法も機能しますが、シングルトンの場合、エンドポイントを実装してBeanを破棄して再作成するか、Bean自体の内部でプロパティのリロードを処理する以外に選択肢はありません。

3.4. @Valueを使用したBeanのリロード

@Value アノテーションには、@ConfigurationPropertiesと同じ制限があります。

4. アクチュエータとクラウドによるプロパティのリロード

Spring Actuator は、ヘルス、メトリック、および構成にさまざまなエンドポイントを提供しますが、Beanを更新するためには何も提供しません。 したがって、SpringCloudに/refreshエンドポイントを追加する必要があります。 このエンドポイントは、 Environment のすべてのプロパティソースをリロードしてから、 EnvironmentChangeEventを公開します。

SpringCloudでは@RefreshScopeも導入されており、構成クラスまたはBeanに使用できます。 その結果、デフォルトのスコープはシングルトンではなくリフレッシュになります。

refresh scopeを使用して、SpringはEnvironmentChangeEventでこれらのコンポーネントの内部キャッシュをクリアします。 次に、Beanへの次のアクセス時に、新しいインスタンスが作成されます。

spring-boot-starter-actuatorpom.xmlに追加することから始めましょう。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

次に、spring-cloud-dependenciesもインポートしましょう。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<properties>
    <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>

次に、spring-cloud-starterを追加します。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter</artifactId>
</dependency>

最後に、更新エンドポイントを有効にしましょう。

management.endpoints.web.exposure.include=refresh

Spring Cloudを使用する場合、プロパティを管理するために Config Server をセットアップできますが、外部ファイルを続行することもできます。 これで、プロパティを読み取る他の2つの方法、@Value@ConfigurationPropertiesを処理できます。

4.1. @ConfigurationPropertiesを使用してBeanを更新します

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

私たちの豆は「 色” ルートからのプロパティ “応用 テーマ” 財産 。  Springのドキュメントによると、setterメソッドが必要であることに注意してください。

外部構成ファイルで「application.theme.color」の値を変更した後、 / refresh を呼び出すことができるので、Beanから新しい値を取得できます。次のアクセス。

4.2. @ValueでBeanを更新します

サンプルコンポーネントを作成しましょう:

@Component
@RefreshScope
public class ValueRefreshConfigBean {
    private String color;

    public ValueRefreshConfigBean(@Value("${application.theme.color}") String color) {
        this.color = color;
    } 
    //put getter here 
}

更新のプロセスは上記と同じです。

ただし、 / refresh は、明示的なシングルトンスコープを持つBeanでは機能しないことに注意する必要があります。

5. 結論

このチュートリアルでは、SpringCloud機能の有無にかかわらずプロパティをリロードする方法を示しました。 また、それぞれのテクニックの落とし穴と例外を示しました。

完全なコードは、GitHubプロジェクト利用できます。