1. 引言

在开发 Spring 应用时,我们常常需要指定某些包来存放实体类(Entity),或者只希望 Spring 初始化特定的组件(Component)。这时就可以借助 @EntityScan@ComponentScan 这两个注解。

先明确一下概念:

  • 组件(Component):指被 @Controller@Service@Repository@Component@Bean 等注解标记的类。
  • 实体(Entity):通常是指使用 JPA 的 @Entity 注解标注的持久化类。

本篇将深入讲解这两个注解的作用和区别,帮助你更清晰地掌握它们的使用场景。

2. @EntityScan 注解详解

在 Spring 应用中,我们经常会定义一些实体类,并通过 @Entity 注解标识。这些实体类一般有两种组织方式:

✅ 放在主应用包或其子包下
❌ 放在一个完全独立的根包中

对于第一种情况,Spring Boot 的自动配置机制(@EnableAutoConfiguration)可以自动扫描到这些实体类。

但如果是第二种情况,就需要手动告诉 Spring 去哪里找这些实体类,这时候就轮到 @EntityScan 出场了。

@Configuration
@EntityScan("com.baeldung.demopackage")
public class EntityScanDemo {
    // ...
}

⚠️ 注意:一旦使用了 @EntityScan,Spring Boot 默认的实体自动扫描机制就会失效!

也就是说,如果你用了这个注解却没有正确配置路径,可能会出现找不到实体类的问题。

3. @ComponentScan 注解详解

@EntityScan 类似,当我们只想让 Spring 扫描并初始化特定组件时,就要用到 @ComponentScan

它的作用是告诉 Spring 在哪些包里查找需要管理的 Bean。

这个注解可以带参数也可以不带:

  • 不带参数时,默认会扫描当前类所在的包及其子包;
  • 带参数时,可以通过 basePackages 指定多个包名,或者通过 basePackageClasses 指定具体类(Spring 会扫描该类所属的包)。

示例代码如下:

@Configuration
@ComponentScan(
  basePackages = {"com.baeldung.demopackage"}, 
  basePackageClasses = DemoBean.class)
public class ComponentScanExample {
    // ...
}

📌 小贴士:@SpringBootApplication 内部其实已经包含了 @ComponentScan,所以大多数情况下你不需要显式添加它。

4. @EntityScan vs. @ComponentScan 对比总结

虽然两者都用于“扫描”包路径,但用途完全不同:

特性 @EntityScan @ComponentScan
用途 指定实体类的位置 指定 Spring 组件的位置
扫描对象 @Entity 标记的类 @Component 系列注解标记的类
是否影响自动配置 ✅ 会关闭默认实体扫描 ❌ 不影响组件自动扫描(除非覆盖)

简单来说:

  • 如果你的实体类不在默认扫描路径,就加上 @EntityScan
  • 如果你想限制 Spring 只加载特定组件,就用 @ComponentScan

5. 结语

本文从实际使用角度出发,对比分析了 @EntityScan@ComponentScan 的作用及差异。理解这两者的职责边界,有助于我们在项目结构设计上更加清晰合理。

下次再遇到扫描不到 Entity 或 Bean 的问题时,不妨回头看看是不是注解没配对 😎


原始标题:Spring @EntityScan vs. @ComponentScan