概要
- Spring Boot でプロファイルを切り替えて実行する
- プロファイルの指定がない場合は Spring Framework では default プロファイルが使われる
- 自前のプロファイルとして development, test, production の3つを用意する
- test と production は一部で同じ要素を使うように構成する
- プロファイルごとの application-*.properties を用意して、記述した値を使用する
- @Profile アノテーションを使用して、指定したプロファイルに対応する bean クラスのオブジェクトを DI (Dependency injection) する
- 複数のプロファイルに対応する bean クラスを用意する
- 複数のプロファイルを指定した場合に対応する
ソースコード一覧
$ tree src
src
├── main
│ ├── java
│ │ └── info
│ │ └── maigo
│ │ └── lab
│ │ └── sample
│ │ └── profiles
│ │ ├── MyData.java
│ │ ├── MyDataForDefault.java
│ │ ├── MyDataForDevelopment.java
│ │ ├── MyDataForTestAndProduction.java
│ │ ├── MyRestController.java
│ │ └── ProfilesApplication.java (←今回は中身を省略)
│ └── resources
│ ├── application-development.properties
│ ├── application-production.properties
│ ├── application-test.properties
│ └── application.properties
基本部分のソースコード
MyRestController.java
Spring Framework の DI 機能で MyData のオブジェクトをインジェクションする。
@Autowired アノテーションをインスタンス変数 myData に記述する。
http://localhost:8080/ へアクセスした際に MyData の情報を JSON で返すようにする。
package info.maigo.lab.sample.profiles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyRestController {
@Autowired
private MyData myData;
@RequestMapping("/")
public MyData index() {
return myData;
}
}
MyData.java
MyData オブジェクトの interface 定義。今回は特にメソッドは用意しない。
package info.maigo.lab.sample.profiles;
public interface MyData {
}
MyDataForDefault.java
default プロファイルで使用する MyData の実装クラス。
@Profile アノテーションで DI するときのプロファイルを指定できる。ここでは default を指定している。
インスタンス変数 profile には文字列 "default" を代入。
インスタンス変数 message には application.properties の message.value を代入。
package info.maigo.lab.sample.profiles;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
@Component
@Profile("default")
public class MyDataForDefault implements MyData {
public String profile = "default";
@Value("${message.value}")
public String message;
}
application.properties
default プロファイルで使用するプロパティファイル。
message.value=Hello, default!
default プロファイルで起動する
ビルドして作った JAR ファイルを指定して起動する。プロファイルを指定するパラメータは付けない。
$ java -jar target/profiles-0.0.1-SNAPSHOT.jar
起動したサーバにアクセスすると default プロファイルの情報が読み込まれているのがわかる。
$ curl http://localhost:8080/
{"profile":"default","message":"Hello, default!"}
development プロファイルで使用するソースコード
MyDataForDevelopment.java
development プロファイルで使用する MyData の実装クラス。
@Profile アノテーションにて develop プロファイルを指定。
インスタンス変数 profile に文字列 "development" を代入。
インスタンス変数 message に application-development.properties の message.value を代入。
package info.maigo.lab.sample.profiles;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
@Component
@Profile("development")
public class MyDataForDevelopment implements MyData {
public String profile = "development";
@Value("${message.value}")
public String message;
}
application-development.properties
development プロファイルで使用するプロパティファイル。
message.value=Hello, development!
development プロファイルを指定して起動する
JVM パラメータ -Dspring.profiles.active に development を指定する。
$ java -Dspring.profiles.active=development -jar target/profiles-0.0.1-SNAPSHOT.jar
起動したサーバにアクセスすると development プロファイルの情報が読み込まれているのがわかる。
$ curl http://localhost:8080/
{"profile":"development","message":"Hello, development!"}
test プロファイルと production プロファイルで使用するソースコード
MyDataForTestAndProduction.java
test プロファイルと production プロファイルで使用する MyData の実装クラス。
@Profile アノテーションに test と production を指定している。指定したいずれかのプロファイルが指定されたときにこのクラスのオブジェクトが DI 対象となる。
@RestController にて返却する JSON の profile は、このクラスの getProfile メソッドにて生成する。Environment#getActiveProfiles で複数指定されたプロファイル名が取得できる。
package info.maigo.lab.sample.profiles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
@Component
@Profile({"test", "production"})
public class MyDataForTestAndProduction implements MyData {
@Autowired
private Environment env;
public String getProfile() {
return String.join(",", env.getActiveProfiles());
}
@Value("${message.value}")
public String message;
}
application-test.properties
test プロファイルで使用するプロパティファイル。
message.value=Hello, test!
application-production.properties
production プロファイルで使用するプロパティファイル。
message.value=Hello, production!
test プロファイルを指定して起動する
JVM パラメータ -Dspring.profiles.active に test を指定する。
$ java -Dspring.profiles.active=test -jar target/profiles-0.0.1-SNAPSHOT.jar
起動したサーバにアクセスすると test プロファイルの情報が読み込まれているのがわかる。
$ curl http://localhost:8080/
{"message":"Hello, test!","profile":"test"}
production プロファイルを指定して起動する
JVM パラメータ -Dspring.profiles.active に production を指定する。
$ java -Dspring.profiles.active=production -jar target/profiles-0.0.1-SNAPSHOT.jar
起動したサーバにアクセスすると production プロファイルの情報が読み込まれているのがわかる。
$ curl http://localhost:8080/
{"message":"Hello, production!","profile":"production"}
複数のプロファイル test と production を指定して起動する
JVM パラメータ -Dspring.profiles.active にカンマ区切りで複数のプロファイル "test,production" を指定する。
$ java -Dspring.profiles.active=test,production -jar target/profiles-0.0.1-SNAPSHOT.jar
起動したサーバにアクセスすると、profile 項目の値に "test,production" と入っているため test と production 両方のプロファイルの情報が読み込まれているのがわかる。
$ curl http://localhost:8080/
{"message":"Hello, production!","profile":"test,production"}
application-test.properties と application-production.properties に定義した message.value の値は、競合した結果 application-production.properties の値が優先された (競合すべき値を設定すべきではないと考えられる)。
試しにプロファイル指定の順番を逆にして "production,test" を指定してみたら、application-test.properties の値が優先された。
$ java -Dspring.profiles.active=production,test -jar target/profiles-0.0.1-SNAPSHOT.jar
$ curl http://localhost:8080/
{"message":"Hello, test!","profile":"production,test"}
おそらく、後から指定したプロファイルが優先される (上書きされる?) と思われる。
今回の環境
- OpenJDK 11
- Spring Boot 2.2.0.M4