はじめに
Spring Bootには、環境変数を外出しする機能があります。
@Valueアノテーションを使うことで、プロパティファイルに記述した設定値をソース内に読み込むことができます。Spring Bootでは、デフォルトでapplication.propertiesまたはapplication.ymlが参照されます。
my.param=test
@Value("${my.param}")
private String param; // "test" の値になる
この@Valueアノテーションによるプロパティ注入が想定通りに効かない場合に考えられる原因をまとめました。
原因1 変数名が違う
当然のことですが、タイプミスや設定漏れなどにより@Valueアノテーションに指定した名前の変数が存在しないと、期待通りに注入されません。
#my.param=test # コメントアウトされている
@Value("${my.param}")
private String param; // null になってしまう
気を付けるべきことではありますが、頻繁に環境を切り替える場合や、開発時にとりあえず動かしたい場合などには、発生してしまうことがあります。
変数名の後ろに:値を付けることで、デフォルト値を設定することができます。
#my.param=test # コメントアウトされている
@Value("${my.param:default}")
private String param; // "default" になる
原因2 注入先のフィールドがstaticで宣言されている
以下のようにstaticキーワードが付いていると、フレームワークは注入することができません。
@Value("${my.param:default}")
private static String param; // nullになってしまう
原因3 クラスを明示的にnewしている
@Value("${my.param:default}")
private String param;
public String getParam() {
return param;
}
MyComponent myComponent = new MyComponent();
String param = myComponent.getParam(); // ここで値が取得できない
newキーワードでインスタンス化した場合は、フレームワークによる注入が効きません。@Serviceや@ComponentなどのアノテーションでBean登録して、フレームワークに管理させましょう。
@Component // 追加
public class MyComponent {
@Value("${my.param:default}")
private String param;
public String getParam() {
return param;
}
}
@Service // 追加
public class MyService {
@Autowired // 追加。インスタンス化はフレームワークに任せる
private MyComponent myComponent;
public void test() {
String param = myComponent.getParam(); // 値が取得できる
}
}
原因4 コンストラクタ内で参照している
@Component
public class MyComponent {
@Value("${my.param:default}")
private String param;
public MyComponent() {
System.out.println(param); // ここでは値が入っていない!
}
public String getParam() {
return param; // ここでは取得できる
}
}
コンストラクタの処理は@Valueアノテーションによる値の注入よりも先に実行されます。そのため、コンストラクタ内では値が取得できません。
コンストラクタ内で環境変数の値を参照したいときは、引数として渡します。
@Component
public class MyComponent {
@Value("${my.param:default}")
private String param;
public MyComponent(@Value("${my.param:default}") String param) {
System.out.println(param); // 値が参照できる!
}
public String getParam() {
return param;
}
}