読者です 読者をやめる 読者になる 読者になる

SIerだけど技術やりたいブログ

5年目のSIerのブログです

Spring Cloud Configのリファレンス読んだ

Spring SpringBoot Java SpringCloud

Spring Cloud Configとは

複数アプリケーション(同一サービス)間で共通の設定を提供するプロダクト。
クライアント-サーバ型のアーキテクチャ

f:id:kimulla:20160304220625p:plain

何がいいの?

  • 複数アプリケーション(同一サービス)間の設定の不一致を避けられる。
  • 再起動なしで設定を再配布できる。

実装方法

Configサーバ

pom.xmlで必要なjarを指定する。

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


@EnableConfigServerをつける。

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}


クライアントに配布する設定ファイルの配置場所をapplication.propertiesで指定する。portは8888が一般的っぽい。

server.port = 8888
spring.cloud.config.server.git.uri = https://github.com/kimullamen/spring-cloud-config-repo.git

githubでもローカルのファイルシステム上にあるgitリポジトリでもok。publicでもprivateなリポジトリでもok。sshでもok。特に制約なし。


リポジトリはアプリごとに1つ用意するのがシンプルでよい。
ファイル名は{app名}-{profile}にする。

https://github.com/kimullamen/spring-cloud-config-repo
f:id:kimulla:20160304212757p:plain


Configサーバといっても、以下のようなエンドポイントを持ったAPサーバ。
(labelはdefaultがmasterで省略可能)

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties


そのため、curlで設定を確認できる。

$ curl -X GET http://localhost:8888/app/production
{
    "name":"app",
    "profiles":[
        "production"
    ],
    "label":null,
    "version":"1469d0351becdfcc a1bffa98f4a07ee685af8255",
    "propertySources":[
        {
            "name":"https://github.com/kimulla men/spring-cloud-config-repo.git/app-production.properties",
            "source":{
                "greeting":"production"
            }
        }
    ]
}
$ curl -X GET http://localhost:8888/app-development.properties
greeting: development

Configクライアント

pom.xmlで必要なjarを指定する。

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


bootstrap.propertiesにconfigサーバのURIを指定する。

spring.cloud.config.uri = http://localhost:8888
spring.application.name = app 
spring.profiles.active = production


bootstrap.propertiesはBootstrapContext※を生成するときに利用するファイル。
Configサーバから取得した設定内容を読み込んだクラスが生成される。

※BootstrapContextはApplicationContextの親コンテキスト。詳細はリファレンスを参照する。


設定を取得できてるか確認するためのControllerを実装する。
@Valueでpropertiesファイルの値を取得できる。(:not-foundは見つからなかったときのデフォルト値)

@RestController
public class GreetingRestController {
    @RequestMapping("/greeting")
    public String greeting(@Value("${greeting:not-found}") String greeting) {
        return greeting;
    }
}

クライアントから見たときのファイル名とアプリの関連性は?

{app名}-{profile}-{label}.properties

app名 spring.application.name
profile spring.active.profiles
label gitのbranch名(デフォルトmaster)

設定変更の反映

いくらgitのファイルを更新しても、アプリ側が設定ファイルを再度読み込むまでは値が反映されない。設定ファイルを再度読み込むためには、/refreshエンドポイントにPOSTすればよい。

細かい理由

  • @ConfigurationPropertiesアノテーションが付与されているクラスは@RefreshScopeになる
  • @RefreshScopeのBeanは/refreshエンドポイントにPOSTするとBeanが再生成される
  • ConfigClientAutoConfigurationクラス内でConfigServicePropertySourceLocatorという設定ファイル読み込み用のクラスが@RefreshScopeになっているため/refreshエンドポイントにPOSTすれば更新されるっぽい
$ curl -X POST localhost:8080/refresh
["greeting"]

でも全部のConfigクライアントに/refreshなんてしたくない

Spring Cloud Busというプロダクトを使えば、Configクライアントから他のConfigクライアントへ更新通知を伝搬できるようになる。また今度調べる。調べた。
kimulla.hatenablog.com