Springで@ConditionalOnBeanを扱うときの注意事項
結論
@ConditionalOnBean
, @ConditionalOnMissingBean
はAutoConfigurationクラス以外では使わない方がいいよ!
@ConditionalOnBean
, @ConditionalOnMissingBean
とは
特定のBeanが存在するときのみ、もしく存在しないときのみにこれらのアノテーションを付与したBeanを有効化することができるアノテーションです。@ConditionalOnBean
を付与したBeanは特定のBeanがApplicationContextに存在する場合有効化され、逆に@ConditionalOnMissingBean
を付与したBeanは特定のBeanがApplicationContextに存在しない場合に有効化されます。
@Configuration
public class SampleConfig {
@Bean
@ConditionalOnMissingBean // sampleServiceというBeanがApplicationContextに存在しない場合にこのBeanが有効化される
public SampleService sampleService() {
return new SampleService();
}
}
なぜAutoConfigurationクラス以外では使わない方がいいのか
公式ドキュメントにも書いてありますが、@ConditionalOnBean
、@ConditionalOnMissingBean
の評価はこれらのアノテーションを付与したBean定義がApplicationContextに追加された時点の情報をもとに行うため、Bean定義の追加順序によっては意図しない結果になる可能性があるからです。
これに気づかず少々ハマってしまいました・・。
@Configuration
@ConditionalOnBean(BConfig.class) // BConfigは定義しているのになぜかAConfigが有効化されないことがある
public class AConfig {
...
}
@Configuration
public class BConfig {
...
}
ではどうするか
他のConditional系のアノテーションで代用できるならそちらで代用すると良いと思います。例えば@ConditionalOnProperty
や@ConditionalOnWebApplication
などであれば上記の制約はなく使うことが可能です。
-
@ConditionalOnProperty
: 特定のプロパティ値がある場合にBeanが有効になる -
@ConditionalOnWebApplication
: アプリケーションがWebアプリケーションの場合にBeanが有効になる
参考
@ConditionalOnBean
、@ConditionalOnMissingBean
はどこで使うべきか
ではそれは最初に書いたようにAutoConfigurationなクラスで使うことが推奨されています。AutoConfigurationクラスにこれらのアノテーションを付与する場合は上記の問題は起こりません。
なぜならAutoConfigurationクラスは必ずユーザが定義したBean定義がApplicationContextに追加された後に読み込まれるためです。
その他参考
Bean定義の読み込みやBeanの生成などBeanのライフサイクルについては以前Qiitaにまとめたのでこちらを参照
Discussion