最初に結論
適切に@ComponentScan
しよう。
前提
以下のように3階層のモジュールがあり、
main-module -> sub-module -> util-module という依存関係であるとする。
このような構成で、sub-module内の@SpringBootTest
が付与されたテストを実行した際
org.springframework.beans.factory.UnsatisfiedDependencyException
が発生してハマったので備忘でメモ。
原因
sub-module内の特定の@Bean
がutil-module内の特定の@Bean
に依存していたが、
コンポーネントスキャンの設定がデフォルトのままとなっており、
util-module内までスキャンしにいかなかったことが原因。
sub-moduleのエントリーポイント(@SpringBootApplication
が付与されたクラス)に
@ComponentScan
のアノテーションを付与し、スキャン対象のパッケージを指定することで解決する。
@SpringBootApplication
public class BootBaseApplication {
public static void main(String[] args) {
SpringApplication.run(BootBaseApplication.class, args);
}
}
@SpringBootApplication
// @ComponentScan("foo.bar.util") sub-module自身のパッケージ内を見に行かなくなるので、これはダメ
@ComponentScan({"foo.bar.sub", "foo.bar.util"})
public class BootBaseApplication {
public static void main(String[] args) {
SpringApplication.run(BootBaseApplication.class, args);
}
}
設定を書かないデフォルト状態ではsub-module内のクラスを自動的にスキャンしてくれるが、
明示的に指定する場合はsub-module自身のパッケージも書かないと、指定したパッケージ(今回はutil-module内)のみしかスキャンしないため注意されたし。
ハマった理由
- subは単品で動作するものではなく、常にmainを起点として動作する構造だったこと
- subを単品で起動することがなかったため、subの
@SpringBootTest
実行まで検知の契機がなかった - mainの起動はできんのになんで?なんかテストユニークの話?という具合でハマった
- subを単品で起動することがなかったため、subの
- mainへのsub追加時に同様の事象が発生しなかったこと
- utilだけパッケージが異なり、mainとsubのパッケージは同じだったため、sub追加時には
@ComponentScan
の設定変更が不要だった - main/subのパッケージ構成が異なっていれば、sub導入時にmainの
@SpringBootTest
実行でも同様の事象が起きていたはず - mainにsub入れるときは起きなかったのに、util入れるときだけ起きたことでまあ混乱
- utilだけパッケージが異なり、mainとsubのパッケージは同じだったため、sub追加時には
- 元々はmain -> subという二階層の依存関係だったところに、別チームが開発したutilを後から追加するという流れだったこと
- 何か特別な設定が必要なのか?前提が違うのか?等々、別チーム成果物に対して若干の不信感があったことも否定できないのでそれは土下座
- 夜遅かったこと
- 疲れが溜まってると些細な不具合にも簡単にハマるという説が有力です
先行研究
同様のエラーの他原因が解説されているので、解決しなかった方はこちら。
Spring BootでNo qualifying bean of typeが出た時の原因と対応
https://qiita.com/NagaokaKenichi/items/058a7243bd2948de7553