しおメモ

雑多な技術系ブログです。

Spring Bootでのプロファイルを使った環境切り分け

Spring Bootでは、プロファイルという機能を用いて、設定値をyamlファイルやpropetiesファイルとして外部に切り分けることができます。
これを使って、実行環境ごとの定数値をまとめたり、DIされるクラスを変えたりすることができます。

今回はyamlの例で解説します。propertiesでも形式以外同じです。

基本

src/main/resources/application.ymlを配置すると、デフォルトでそこに記述した設定値がロードされます。

spring:
  thymeleaf:
    cache: false

ここで、記述した値は上書きされない限り、どの環境でも同じです。

各環境の設定ファイルは、application-xxx.ymlという名前でファイルを作ると、プロファイルとして自動で参照できるようになります。
(明示的にプロファイル名をファイル内に記述する方法もあります。)

application-dev.ymlという名前のファイルを用意した場合、プロファイル名は、devになります。
こちらをデフォルトのプロファイルとして指定する場合は、application.ymlに以下のように記述します。

spring:
  profiles:
    active: dev

実行時に読み込むプロファイルの指定

System Propertiesやコマンドライン引数や、環境変数で設定できます。
jar起動の場合、

# Java System Properties
java -jar -Dspring.profiles.active=prod hoge.jar
# コマンドライン引数
java -jar hoge.jar --spring.profiles.active=prod

です。

環境変数の場合は、SPRING_PROFILES_ACTIVEを設定します。
(IntelliJ Ultimateなど一部のIDEでは、GUIから指定できます)

クラスを環境ごとに切り替える

@Profileを使うと、指定したプロファイルが有効な時に、そのクラスがロードされます。

例えば、proddevの場合に使う、それぞれHogeというインタフェースを実装する、HogeDevHogeProdの2つのクラスを用意したい場合、

@Profile("dev")
public final class HogeDev implements Hoge { ... }

@Profile("prod")
public final class HogeProd implements Hoge { ... }

のようになります。

また、@Profile("{dev, prod}")のように、複数のプロファイルを指定することもできます。

値を切り替える

プロパティにプロファイルから読んだ値を設定したい場合、@Valueを利用します。
例えば、試験環境と本番環境のAPIのアドレスを変えたい時は、

@Value("${api.endpoint}")
private String endpoint;
api:
  endpoint: http://localhost:3000/v1/

と書くと、初期値としてyamlから読まれた値が設定されます。

Spring BootのDIコンテナを使う

Spring Bootの@Autowiredは、インターフェースにも利用できます。
その場合、実装が1つならばうまく注入してくれるので、先ほどの@Profileを利用して実装します。

public final class HogeGovernor {
    @Autowired
    private Hoge hoge;
}
@Component
@Profile("prod")
public final class HogeProd implements Hoge { ... }

このようにすると、スッキリ実装を切り替えることができます。

テストでもプロファイルを使う

ユニットテスト時には、@ActiveProfilesを用いることで、有効なプロファイルを指定することができます。(複数も可)

@ActiveProfiles("dev")
public final class HogeTest { ... }

こうすることで、各テストケースの実行時にはdevプロファイルが読み込まれた状態となります。