您应该想知道的第一件事是:为什么要声明 @ComponentScan 而 @SpringBootApplication 的目标之一是(除其他外)启用组件扫描?
来自Spring Boot documentation:
@SpringBootApplication 注解等价于使用
@Configuration、@EnableAutoConfiguration 和 @ComponentScan 与他们的
默认属性
请注意,当您在 Spring Boot 应用程序的类上声明 @ComponentScan 以将值指定为 basePackages 时,它会覆盖 @SpringBootApplication 默认使用的 basePackages,即该类所在的当前包居住。因此,要将 Spring Boot Application 类的包和缺少的附加包都作为基础包,您必须显式设置它们。
除了basePackages 是递归的。因此,要对位于"org.example" 和"org.example.model" 包中的类启用扫描,指定"org.example" 就足够了,因为"org.example.model" 是它的子包。
试试看:
@SpringBootApplication(scanBasePackages={"org.example"})
或者:
@SpringBootApplication
@ComponentScan("org.example")
在 Spring Boot 应用程序中指定 @EnableJpaRepositories/@ComponentScan/scanBasePackages 时?
当您设计 Spring Boot 应用程序布局时,您有两种情况:
1) 使用包布局的情况(支持),该包布局提供零配置的 Spring Boot 自动配置。
总结一下:如果您的类使用 Spring Bean 原型注解:@Component、@Repositories、@Repositories,... 位于 Spring Boot Application 类的同一包或子包中,仅声明
@SpringBootApplication 就是你所需要的。
2) 不使用提供零配置的 Spring Boot 自动配置的包布局的情况(避免)。
这通常意味着您要扫描的候选类不在您的类的包(或子包)中,并带有@SpringBootApplication 注释。
在这种情况下,您可以添加 scanBasePackages 属性或添加 @ComponentScan 以指定要扫描的包。
但此外,如果您的存储库不在您的类的包或子包中,并使用@SpringBootApplication 注释,则必须声明其他内容,例如:@EnableJpaRepositories(="packageWhereMyRepoAreLocated")
Here is the documentation关于这部分(重点是我的):
80.3 使用 Spring 数据存储库
Spring Data 可以创建 @Repository 接口的实现
各种口味。 Spring Boot 会为您处理所有这些,只要
那些@Repositories 包含在同一个包中(或
@EnableAutoConfiguration 类的子包)。
对于许多应用程序,您只需要放置正确的 Spring Data
对你的类路径的依赖(有一个
用于 JPA 的 spring-boot-starter-data-jpa 和
spring-boot-starter-data-mongodb for Mongodb)并创建一些
存储库接口来处理您的 @Entity 对象。例子在
JPA 示例和 Mongodb 示例。
Spring Boot 尝试猜测您的 @Repository 的位置
定义,基于它找到的@EnableAutoConfiguration。要得到
更多控制,使用 @EnableJpaRepositories 注释(来自 Spring
数据 JPA)。
示例
1) 使用包布局的情况(支持),该包布局提供零配置的 Spring Boot 自动配置。
对于在org.example包中声明的Spring Boot应用程序,以及在同一包或org.example的子包中声明的所有bean类(包括Repositories),以下声明对于Spring Boot应用程序就足够了:
package org.example;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
存储库可以位于org.example.repository 包中,例如:
package org.example.repository;
@Repository
public interface FooRepository extends JpaRepository<Foo, Long>, { }
和
package org.example.repository;
@Repository
public interface BarRepository extends JpaRepository<Bar, Long>, { }
控制器可能位于org.example.controller 包中:
package org.example.controller;
@RestController
@RequestMapping("/api/foos")
public class FooController {...}
等等……
2) 不使用提供零配置的 Spring Boot 自动配置的包布局的情况(避免)。
对于在org.example.application 包中声明的 Spring Boot 应用程序,而不是在同一包或 org.example.application 的子包中声明的所有 bean 类(包括存储库),Spring Boot 将需要以下声明应用:
package org.example.application;
@SpringBootApplication(scanBasePackages= {
"org.example",
"org.thirdparty.repository"})
@EnableJpaRepositories("org.thirdparty.repository")
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
bean 类可能如下所示。
可能来自外部 JAR 的存储库可能位于 org.thirdparty.repository 包中,例如:
package org.thirdparty.repository;
@Repository
public interface FooRepository extends JpaRepository<Foo, Long>, { }
和
package org.thirdparty.repository;
@Repository
public interface BarRepository extends JpaRepository<Bar, Long>, { }
控制器可能位于org.example.controller 包中:
package org.example.controller
@RestController
@RequestMapping("/api/foos")
public class FooController {...}
等等……
结论:确实鼓励在命名空间的基础包中定义 Spring Boot 应用程序,以使 Spring Boot 配置尽可能简单。