概要
SpringBoot2.4以降、設定ファイル(application.yml
の類)の処理方法がガラッと変わっている。1
SpringBoot2.x系を使っている分には、2.3以前の処理方法をonにするオプション(spring.config.use-legacy-processing
)を利用できるが、SpringBoot3に追随する場合は左記のオプションは使えないので、新しい処理方法への適応が必須である。2
ここではこのSpringBoot2.4で入った設定ファイルの処理方法変更の背景、変更内容、spring-cloudへの影響を記述する。
設定ファイル処理方法の変更が入った背景
そもそもこのような変更が必要となった背景はSpring公式のこのブログに記載されている。
要約すると、KubernetesのConfigMap
の設定読み取りに対応しつつ、従来の方法も提供し続けたいが、2.3以前の設定ファイルを処理するクラスであるConfigFileApplicationListener
を使い続けるのは厳しいため、新たな仕組みへと刷新することにした、という内容であった。
Kubernetesの
ConfigMap
の設定読み取りに対応しつつ
ここについてもう少し詳しく記述すると、Kubernetesにおいてはファイルのディレクトリをキーとし、ファイルの内容を値とする設定方法があり、SpringBoot2.4以降はその読み取りに対応できるようになっている。
従来の方法と新しい設定方法を比較してみる。
従来のapplication.yml
から下記のような設定値を読み取ることができる。
myapp:
username: nannany
password: dolphins
ファイルのディレクトリをキーとし、ファイルの内容を値とする設定で同様のことをしようとした場合、下記のようなディレクトリ構造をしていて、username
ファイルの中にnannany
という値、password
ファイルの中にdolphins
という値が含まれている、というイメージである。3
/etc
└── config
└── myapp
├── username
└── password
SpringBoot2.4以降では、上記のどちらからも設定を取得することができるようになっている。
どんな変更が入っている?
入った変更は下記ページがよくまとまっている。
-
application.properties
でも#---
を使ったら1つのファイルを論理的に分割することができるようになった-
application.yml
では---
を使って以前から分割できていた
-
-
spring.config.activate.on-profile
でactivateなprofileを切り替えることができるようになった-
spring.profiles.active
との共存に関しては、論理的に分割された別の範囲で共存することは可能。論理的にも一緒の部分で共存することは不可
-
test=value
spring.profiles.active=local
#---
spring.config.activate.on-profile=dev
test=overridden value
test=value
#---
spring.config.activate.on-profile=dev
spring.profiles.active=local # will fail
test=overridden value
- 複数のprofileを1つのグループにまとめることができるようになった
spring.profiles.group.prod=proddb,prodmq,prodmetrics
-
spring.config.import
で読み取るべき設定ファイルの指定、kubernetes likeな設定値の読み取りができるようになった- 肝の機能と思われる
- 複数のキーバリューが設定してある設定ファイルから設定読み取りができる
- ディレクトリをキー、ファイル内容をバリューとした設定からの読み取りができる
spring.config.import=file:/etc/config/myconfig.yaml
spring.config.import=optional:configtree:/etc/config/
- クラウドプラットフォームによってアクティブにするか切り替えられる
spring.config.activate.on-cloud-platform
が用意された- kubernetesだけでなく、cloudfoundry、heroku、sap、azureappserviceが(おそらく)デフォルトで指定できる4
spring.config.activate.on-cloud-platform=kubernetes
spring.config.import=configtree:/etc/config
- 2.3以前の処理方法を継続したい人のために
spring.config.use-legacy-processing
オプションが用意された
spring-cloudへの影響
spring-cloud側でもこの変更の影響を受けていて、例えばspring-cloud-commons内のConfigDataMissingEnvironmentPostProcessor.java
では下記のようにspring.config.import
が設定されていないと落ちることがある。5
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
if (!shouldProcessEnvironment(environment)) {
return;
}
List<Object> property = getConfigImports(environment);
if (property == null || property.isEmpty()) {
throw new ImportException("No spring.config.import set", false);
}
if (!property.stream().anyMatch(impt -> ((String) impt).contains(getPrefix()))) {
throw new ImportException("spring.config.import missing " + getPrefix(), true);
}
}
私自身、SpringBootとspring-cloudのバージョンを上げた際に、ユニットテストが上記のエラー分岐に入るようになって下記のエラーメッセージに直面した。
Caused by: org.springframework.cloud.commons.ConfigDataMissingEnvironmentPostProcessor$ImportException: No spring.config.import set
ユニットテストであったので、spring-cloud-configを無効にすべくspring.cloud.config.enabled=false
にして対処することができた。
(直面した事象ベースで記述しており、ここ以外にもspring-cloudへの影響はあると思う)
まとめ
SpringBoot2.4で大きく変更の入った設定ファイルの処理方法について、変更の背景・変更内容・spring-cloudへの影響(の一例)を記述した。
雑感として、SpringBootのドキュメントは色々あって本当に充実しているなぁと感じる一方、spring-cloud側はもうちょっと変更の影響をガイドする何かがあっても良いのでは、と思った。 -> ちゃんとみたらあった
https://spring.pleiades.io/spring-cloud-config/docs/current/reference/html/#config-data-import
追加で面白そうだと感じたのは、ここ に書いてあるのだが、spring.config.import
設定ファイル読み込みはプラガブルで、ConfigDataLocationResolver
、ConfigDataLoader
を実装すれば独自のサポートが可能らしい。
実際、spring-cloud-config-clientでは、下記のようにconfigserver
なる文字列を利用した独自の指定が可能となっている。
spring.config.import=optional:configserver:http://myconfigserver.com
参考
-
Config file processing in Spring Boot 2.4
- 変更の経緯・変更内容が記されている
-
Spring Boot 2.4で導入されたConfig TreeでKubernetesのSecretの値をSpring Bootアプリのプロパティに設定
- configtreeで設定値を取得する実例が載っている。諸々の背景も詳しく書いてある
-
CloudPlatform.java。このコードに出てくるものを列挙した ↩