Spring Cloud Configを使って、アプリケーションが使う環境毎に異なる設定値をちゃんと構成管理してみる。
Spring Cloud Configは、設定値をAPIで配信するConfig Serverが必要となる。アプリケーションは、Config Serverから環境に応じた設定値を取得して動作する感じになる。
Config Serverを作ってみる
Config Serverは、org.springframework.cloud:spring-cloud-config-serverを追加するだけで簡単に作成できる。
Gradleの場合はこんな感じになる。
dependencies {
implementation('org.springframework.cloud:spring-cloud-config-server')
}
あとは、Spring Bootのアプリケーションと同じように起動クラスを作るだけで良い。
ポイントは、@SpringBootApplicationアノテーションだけではなく@EnableConfigServerをつけていること。
@EnableConfigServer @SpringBootApplication class ConfigServer fun main(args: Array<String>) { runApplication<ConfigServer>(*args) }
application.propertiesには、設定値が置かれたリポジトリの情報を設定する。
server.port=8888 spring.cloud.config.server.git.uri=git@bitbucket.org:siosio/config.git spring.cloud.config.server.git.private-key=${key} spring.cloud.config.server.git.passphrase=${pass}
設定値を保持するpropertiesファイルを作って、gitにpushする。
propertiesファイルの名前は、<アプリケーション名>-<プロファイル名>.propertiesとして、ルートディレクトリにおいておく。*1
今回は、application-dev.propertiesとしておく。
hello.message=hello!!!
設定値を使うアプリケーションを作ってみる
アプリケーション側には、spring-cloud-starter--configを追加する。あとは、Config Serverで管理している設定を変更した時にアプリケーション側の値をリフレッシュするためにspring-boot-starter-actuatorも追加しておく。
implementation 'org.springframework.cloud:spring-cloud-starter--config' implementation 'org.springframework.boot:spring-boot-starter-actuator'
設定値を保持するコンポーネントを定義します。
これで、Config Serverから取得したhello.messageの値がmessageプロパティに保持されます。
@ConfigurationProperties(prefix = "hello") @Component class HelloProperties { lateinit var message: String }
Config Serverで管理している設定値が使えていることを確認するAPIを作ります。
Propertiesクラスで保持している設定値と、@Valueで直接設定値をインジェクションした場合の確認をします。
@RestController @RequestMapping("/hello") class HelloController( private val prop: HelloProperties, @Value("\${hello.message}") private val message: String ) { @GetMapping fun hello(): Res { return Res(prop.message, message) } } data class Res( val propMessage: String, val valueMessage: String )
resources/bootstrap.propertiesを作成して、Config Serverの指定などをします。
spring.application.nameに、Config Serverのpropertiesファイル名に指定したアプリケーション名を設定します。
spring.cloud.config.uriに、Config Serverのuriを指定します。(デフォルトは、http://localhost:8888になっています)
spring.application.name=application spring.cloud.config.uri=http://localhost:8888
動かしてみる
Config Serverのpropertiesファイル名に指定したプロファイル(dev)をアクティブにしてアプリケーションを起動します。
java -jar -Dspring.profiles.active=dev web-app-0.0.1-SNAPSHOT.jar
curlでAPIを叩いてみると、Config Serverで管理されている値が返されることがわかります。
curl http://localhost:8080/hello {"propMessage":"hello!!!","valueMessage":"hello!!!"}
Config Serverで管理されている設定値を変更し、アプリケーション側で設定値を再読込してみます。
設定値をmod hello!!!に変更してみます。
$ cat application-dev.properties hello.message=mod hello!!! $ git commit -a -m mod [master bed53e2] mod 1 file changed, 1 insertion(+), 1 deletion(-) git push origin master
actuatorのrefreshエンドポイントを叩いて、設定値を再読込します。
アプリケーション側には、再読込したよを示すログが出力されます。
$ curl -X POST http://localhost:8080/actuator/refresh ["config.client.version","hello.message"]
再度APIを叩いてみると、Propertiesクラスが持つ設定値は最新化されていますが、@Value でインジェクションした値は変わっていないことがわかります。
$ curl http://localhost:8080/hello {"propMessage":"mod hello!!!","valueMessage":"hello!!!"}
@Valueでインジェクションした値も再読込したい場合は、下のように該当クラスに@RefreshScopeをつけてあげます。
@RestController @RequestMapping("/hello") @RefreshScope class HelloController( private val prop: HelloProperties, @Value("\${hello.message}") private val message: String )
@RefreshScopeをつけたことで、refresh後に@Valueの値も最新化されるようになりました。
$ curl http://localhost:8080/hello {"propMessage":"mod hello!!!","valueMessage":"mod hello!!!"} $ cat application-dev.properties hello.message=mod mod hello!!! $ git commit -a -m mod [master a468229] mod 1 file changed, 1 insertion(+), 1 deletion(-) siosio@siosio:~/IdeaProjects/temp/config$ git push origin master $ curl -X POST http://localhost:8080/actuator/refresh ["config.client.version","hello.message"] $ curl http://localhost:8080/hello {"propMessage":"mod mod hello!!!","valueMessage":"mod mod hello!!!"}
おわり。
*1:ファイルの命名規則は、 Spring Cloud Configを参照