アレについて記す

Spring Bootで実行環境ごとに設定を切り替える

Posted on January 30, 2015 at 23:16 (JST)

Spring Bootで実行環境ごとに値を切り替える方法について記述します。
DB接続情報やキャッシュのON/OFFなど、開発時と本番稼働時に設定を切り替えたい設定が多々あります。
Spring Bootでは上記のような用途に対し、Profileという仕組み(概念)を用意しています。

作成したサンプルはGithubにて公開しています。[ simple-mvc-app-env-val ]

application.ymlの分離とProfileの指定

[設定ファイルの用意]

まず、Profile名を決めます。今回は下記にしました。

  • 開発環境: dev
  • 本番環境: production

次に、設定ファイルを用意します。
設定ファイルの配備
resources/configディレクトリを作成し、その下に3ファイル用意しました。

[ application.yml ]

spring:
  profiles:
    active: dev

上記のファイルは、Profileの指定がなかった場合のデフォルト値を記述しています。

実際に値を設定しているのは、application-dev.ymlapplication-production.ymlです。
application-${Profile名}.ymlを用意すると、該当するファイルの設定が使用されます。

[Profileを指定して実行]

Profileはビルド成果物のjarを実施する際に、引数にて指定することが出来ます。
今回のサンプルにて本番用のプロファイルを指定する場合、コマンドは下記になります
$ java -jar -Dspring.profiles.active=production build/libs/simple-mvc-app-env-val-1.0.jar

[テスト時の設定ファイル]

単体テスト実施時はtest/resources下の設定ファイルが優先的に読み込まれます。
application.ymlをテスト用に作成し、activeプロファイルをtestとすればapplication-test.ymlの設定値でテスト可能です。

外部パラメータの受け取りと、Configクラスへの設定

[外部パラメータの受け取り]

Spring Bootでは下記の箇所(※1)に指定した値を、アプリケーション内で利用出来ます。

  1. コマンドライン引数
  2. JavaのSystem properties
  3. OSの環境変数
  4. jarの外側の設定ファイル
複数箇所で同じプロパティ名の値が指定された場合、上記の番号順で優先されます。(1が最優先)

[外部パラメータの使用]

Configクラス内で使用する方法は2通りあります。

  1. @Valueを使用する
  2. @ConfigurationPropertiesを使用する
まずは、@Valueを使用するサンプルから見ていきます。

[ ExternalizedConfig.java ]

@Component
//@Configuration ←どちらでも可
public class ExternalizedConfig {  
    /** 最初から用意されている変数 */
    @Value("${spring.profiles.active}")
    private String activeProfile;  
    /** コマンドラインから設定する値 */
    @Value("${message}")
    private String message;  
    /** アプリケーション内の設定ファイルの値 */
    @Value("${env.name}")
    private String name;  
    /** keyがアンダースコア区切りの値 */
    @Value("${UNSCO_VAL}")
    private String unscoVal;  
    /** 環境変数の利用 */
    @Value("${JAVA_HOME}")
    private String javaHome;  
    /** 環境変数の利用(設定ファイル経由) */
    @Value("${jHome}")
    private String jHomeViaFile;  
    < 以下、Getter省略 >
}

@Valueに指定されたプロパティ名と同じkeyで値が設定されている場合、Configクラスにその値がセットされます。
大文字小文字や区切り文字が異なる場合には値が設定されません。
なお、指定されたプロパティ名に対して、値がどこにも設定されていない場合はエラーとなります。
上記例の場合、messageは設定ファイルを含めどこにも設定していないため、コマンドライン引数で渡さない場合エラーとなります。

つづいて、@ConfigurationPropertiesを使用する例を見てみましょう。

[ ExternalizedConfig.java ]

@Configuration
@ConfigurationProperties(prefix="rel")
public class RelaxedConfig {
    @NotNull
    private String unscoVal;
    private String name;  
    < 以下、Seetter/Getter省略 >
}

prefix+フィールド変数名に該当する値が設定されます。
上記の場合、rel.unscoValやrel.nameが指定されていれば、その値が設定されます。
注意点として、こちらの設定方法は Relaxed binding と呼ばれる挙動で値が設定されます。
REL_UNSCO_VALやrel.UNSCO_VAL、rel.NAMEといったプロパティ名であっても、値が設定されます。

また、該当する値がない場合はエラーとならない点や、setterを用意しないと値が設定されない点も注意が必要です。
値が必須である場合は@NotNULLを付与することで、起動時チェックで拾うことが出来ます。

[使用方法]

サンプルではControllerで@Autowiredを使用してConfigクラスを読みこみ、画面へ値を表示してみました。

[ HomeController.java ]

@Controller
@RequestMapping("/")
class HomeController {
    @Autowired
    ExternalizedConfig externalizedConfig;
    @Autowired
    RelaxedConfig relaxedConfig; 
    @RequestMapping(method = RequestMethod.GET)
    public String index(Model model) {
        model.addAttribute("relConf", relaxedConfig);
        model.addAttribute("extConf", externalizedConfig);
        model.addAttribute("javaHomeViaController", System.getenv("JAVA_HOME"));
        return "index";
    }
}

$ java -jar -Dspring.profiles.active=production build/libs/simple-mvc-app-env-val-1.0.jar --message="温泉行きたい" --UNSCO_VAL=ggg_zzz --rel.name=Zen 上記コマンドを実行した結果が下記になります。
外部設定値を表示
実際は@Componentを付与したクラスにて、@Beanを付与したメソッドにて読みこんだ値を使用するのが一般的だと思います。

外部パラメータの受け取りと、Configクラスへの設定

[外部パラメータの受け取り]

Spring Bootでは下記の箇所(※1)に指定した値を、アプリケーション内で利用出来ます。

  1. コマンドライン引数
  2. JavaのSystem properties
  3. OSの環境変数
  4. jarの外側の設定ファイル
複数箇所で同じプロパティ名の値が指定された場合、上記の番号順で優先されます。(1が最優先)

[特定のProfileが指定された場合にだけ、特定のコンフィグクラスを読み込む]

@Profileを使用することで条件を付与出来ます。
前回記載したH2DBのコンソール立ち上げを開発時のみに適用したい場合、下記のように設定します。

[ ExternalizedConfig.java ]

@Configuration
@Profile("dev")
public class H2ServerConfig {
    // H2コンソールを使用可能にする。
    @Bean(name = "h2Server", initMethod = "start", destroyMethod = "stop")
    @DependsOn(value = "h2WebServer")
    Server createTcpServer() throws SQLException { 
    < 中略 >
}

※1:外部変数の指定方法は他にもいろいろあります。詳しくは公式ドキュメントの23. Externalized Configurationをご参照ください。

以上です。