【Spring】Spring BootでのデフォルトのConponent Scan
Spring Initializrで生成したばかりのSpring Bootプロジェクトからアプリを実行すると、Component Scanの対象となるパッケージがデフォルトでトップレベルから実行されていることがわかります。
これは、下記の様な @SpringBootApplication
アノテーションが付与されたクラスがトップレベルのパッケージに配置されているためです。
// PlaygroundApplication.kt @SpringBootApplication class PlaygroundApplication fun main(args: Array<String>) { runApplication<PlaygroundApplication>(*args) }
@SpringBootApplication
アノテーションには @ComponentScan
アノテーションが付与されており、その引数には basePackages
指定がありません。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), // basePackage指定なし @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) @ConfigurationPropertiesScan public @interface SpringBootApplication { ... }
basePackages
指定のない @ComponentScan
は、アノテーションを付与したクラスが属するパッケージ階層以下をスキャン対象とします。
そのため、例えば PlaygroundApplication
クラス(kotlinであればこのクラスを含む.ktファイル)が下図のように配置されている場合、そのComponent Scan対象は PlaygroundApplication
が属するパッケージ階層以下となります。
com └── springapp ├── PlaygroundApplication.kt // PlaygroundApplicationクラスを定義 ├── ServletInitializer.kt ├── application │ └── config │ └── AppConfig.kt └── domain ├── model ...
この理由から、 PlaygroundApplication.kt
を別のパッケージ階層に移動すると、そのパッケージ配下のコンポーネントだけがスキャン対象となり、上位のパッケージ及び別階層のパッケージのスキャンは実施されません。
com └── springapp ├── ServletInitializer.kt ├── app │ └── PlaygroundApplication.kt ├── application │ └── config │ └── AppConfig.kt // スキャンされない! └── domain ├── model
*************************** APPLICATION FAILED TO START *************************** Description: Parameter 0 of constructor in com.springapp.domain.service.UserService required a bean of type 'com.springapp.domain.repository.UserRepository' that could not be found. The injection point has the following annotations: - @org.springframework.beans.factory.annotation.Autowired(required=true) ...
なお @SpringBootApplication
で明示的にスキャン対象を指定する場合、 scanBasePackages
プロパティを使用します。
@SpringBootApplication(scanBasePackages={"com"}) class PlaygroundApplication fun main(args: Array<String>) { runApplication<PlaygroundApplication>(*args) }