yoshikipom Tech Blog

Spring Boot外部設定(application.yml)の保守性を上げる

Overview

spring bootの設定ファイルの保守性を上げる

  • spring boot 2.7.0
  • 設定ファイルはyml形式を使用

保守性をあげるために設定ファイルに求めること

  • 環境に応じて切替可能
  • ファイル分割(コンフリクトを避ける、設定がみつけやすい)
  • 外部からの値の注入(シークレット情報を扱う場合は重要)
  • 起動の簡単さ(必須設定が多すぎると新規開発者が苦労する)

Spring Bootの機能

基本

設定ファイルとそれを読み込むConfigクラスを準備。(@Valueでも同様に動くが今回は省略。)

src/main/resources/application.yml

myapp:
  configTest:
    key: value
    env_test: ${ENV_TEST}
    noenv: ${NO_ENV:default_value}
    flag: true
    env: no_env

ConfigTest.java

@Data
@ConfigurationProperties(prefix = "myapp.config-test")
@Component
public class ConfigTest {

  private String key;
  private String key2 = null;
  private String envTest;
  private String noenv;
  private boolean flag;
  private String env;
}

読み込みはAutowiredして呼びたい設定のgetterを呼べばOK。 (ここではテスト結果が見やすいようにtoString()を読んでます。)

@SpringBootApplication
@Slf4j
public class ConfigApplication implements CommandLineRunner {

  @Autowired
  private ConfigTest configTest;

  public static void main(String[] args) {
    SpringApplication.run(ConfigApplication.class, args);
    System.exit(0);
  }

  @Override
  public void run(String... args) throws Exception {
    log.info(configTest.toString());
  }
}

実行ログ

2022-08-21 20:39:03.100  INFO 62961 --- [           main] c.y.dev.config.ConfigApplication         : ConfigTest(key=value, key2=null, envTest=injected_value, noenv=default_value, flag=true, env=no_env)

profile

  • application.yml, application-dev.yml, application-prod.yml を準備
  • dev環境: export spring_profiles_active=dev してからアプリ実行 -> application-dev.yml が読まれる
  • prod環境: export spring_profiles_active=prod してからアプリ実行 -> application-prod.yml が読まれる

src/main/resources/application-dev.yml

myapp:
  configTest:
    env: dev

環境変数spring_profiles_active=devを設定して実行ログ確認

2022-08-21 16:59:05.057  INFO 61874 --- [           main] c.y.dev.config.ConfigApplication         : The following 1 profile is active: "dev"
...
2022-08-21 16:59:07.101  INFO 61874 --- [           main] c.y.dev.config.ConfigApplication         : ConfigTest(key=overwritten_by_external, key2=null, envTest=injected_value, noenv=default_value, flag=true, env=dev)

env=devになっているのでうまく動作している。

参考 https://www.baeldung.com/spring-profiles https://spring.pleiades.io/spring-boot/docs/current/reference/html/features.html#features.external-config.files.profile-specific

外部ファイル読み込み

src/main/resources/application.yml (追記)

spring:
  config:
    import:
      - "another.yml"
      - "optional:file:./spring-mvc/dev/external-config.yml"
  • importで複数ファイル指定可能。
  • 絶対パスor相対パスでJARファイル外のファイルも指定可能
  • 同じ値が設定されている場合は後に設定したものが優先。

src/main/resources/another.yml

myapp:
  configTest:
    key: overwritten_by_another

spring-mvc/dev/external-config.yml

myapp:
  configTest:
    key: overwritten_by_external

実行ログ

2022-08-21 16:59:07.101  INFO 61874 --- [           main] c.y.dev.config.ConfigApplication         : ConfigTest(key=overwritten_by_external, key2=null, envTest=injected_value, noenv=default_value, flag=true, env=dev)

external-config.ymlが優先されるので値はkey=overwritten_by_externalとなっている。

https://spring.pleiades.io/spring-boot/docs/current/reference/html/features.html#features.external-config.files

環境変数読み込み

「基本」の env_test: ${ENV_TEST} を参照。${}内で指定した環境変数が自動で展開される。このプレースホルダは設定ファイル内の他の値を展開したり文字列の結合したりも可能。 https://spring.pleiades.io/spring-boot/docs/current/reference/html/features.html#features.external-config.files.property-placeholders

default値の設定

環境変数が設定されない場合 env_test: ${ENV_TEST:default-value} のように書ける。

他の値はJava class側のコンストラクタで設定しておけばデフォルトを持てるが、設定ファイル側に入れておいたほうが見やすい。

ConfigTest.java

@Data
@ConfigurationProperties(prefix = "myapp.config-test")
@Component
public class ConfigTest {
  private String key = "default-value";
  ...

環境変数 vs profile

環境変数でもprofileでも環境ごとの値の設定は可能。 - 環境変数 - シークレットを扱いやすい - 値の変更が容易 - yamlのような構造がないのでリスト型や辞書型の設定は持ちづらい - profile - 構造があるので多数の設定やリスト型、辞書型の設定も扱いやすい - シークレットを使うなら結局プレースホルダーで環境変数を入れることになりそう - JARに設定ファイルを入れているなら値の変更に再度ビルドが必要 設定値が少ないうちは環境変数で環境差異を吸収するのが良さそう。

感想

Spring Bootの外部設定管理まわりは機能が多くて、同じことを複数のやり方でできることが多い。 何を使って何を使わないか決めておくのがよさそう。

参考