@AutoConfigurationPackage 和 @ComponentScan 有何区别?

首先,从名字上看,这两个注解意义特别接近,@AutoConfigurationPackage 就是自动配置包,自动配置包的目的是能让系统扫描到包内的 Bean;@ComponentScan 则是组件扫描,这个松哥在之前的教程中也多次提到过了,就不再赘述了,所以这里就有一个问题,这两个注解有啥区别?

首先大家思考这样一个问题:

现在大多数项目可能都是用的 MyBatis 或者 MyBatis-Plus 这样的数据持久化框架,当我们在 Spring Boot 中使用 MyBatis 的时候,我们一般需要在 Mapper 接口上添加一个 @Mapper 注解,类似下面这样:

@Mapper
public interface UserMapper {
}

或者在启动类上加 Mapper 扫描注解去统一扫描所有的 Mapper 接口,类似下面这样:

@SpringBootApplication
@MapperScan(basePackages = "org.javaboy.auto_package")
public class AutoPackageApplication {

    public static void main(String[] args) {
        SpringApplication.run(AutoPackageApplication.class, args);
    }

}

平时我们都这样写,没有任何问题,现在假设我们换一个写法,假如我的类结构如下:

├── main
│   ├── java
│   │   └── org
│   │       └── javaboy
│   │           └── auto_package
│   │               ├── config
│   │               │   ├── AutoPackageApplication.java
│   │               │   └── UserController.java
│   │               ├── mapper
│   │               │   └── UserMapper.java
│   │               └── service
│   │                   └── UserService.java

小伙伴们看到,我把启动类和 UserController 放在一个单独的包中,UserMapper 和 UserService 也分别位于不同的包中,其中在 UserController 中注入了 UserService,在 UserService 中则注入了 UserMapper,大致上就这么一个关系。

按照我们之前对 Spring Boot 的理解,这个项目启动肯定会报错,因为默认情况下,系统扫描的 Bean 是启动类所在的包以及子包下的所有 Bean(因为 @SpringBootApplication 注解在启动类上),所以上面这个项目启动的时候,能扫描到 UserController,但是扫描不到 UserService,所以启动的时候会报错,如下:

大家看下,这意思很明确,UserService 找不到,所以启动失败。

解决这个问题的办法很简单,要么将启动类放到根包下面,这样所有的 Bean 默认就都能扫描到了,要么我们重新配置包扫描,这里我采用第二种方案,我们在启动类上加 @ComponentScan 注解,重新指定扫描的包,如下:

@SpringBootApplication
@ComponentScan(basePackages = "org.javaboy.auto_package")
public class AutoPackageApplication {

    public static void main(String[] args) {
        SpringApplication.run(AutoPackageApplication.class, args);
    }

}

加上之后,我们再次启动,发现又报错了,如下:

虽然再次出错,但是跟之前的错误并不一样,这次是没找到 UserMapper 这个 Bean,说明 UserService 是找到了!

从这里我们就可以看出来,@ComponentScan 注解扫描组件是不会扫描到 @Mapper 注解的!

事实上,@ComponentScan 注解主要是扫描 Spring 家族的各种 Bean,如 @Controller、@Service、@Component、@Repository 以及由此衍生出来的一些其他的 Bean,对于 Spring 家族之外的 Bean,如 MyBatis 的 @Mapper、@MapperScan,JPA 的 @Entity 等,@ComponentScan 都扫不到!

谁能扫到呢?那就是我们今天的另外一个主角 @AutoConfigurationPackage,这个注解其实就是专门用来扫这些第三方的各种 Bean 的。

现在,我们在项目启动上加上 @AutoConfigurationPackage 注解,并设置需要扫描的位置,如下:

@SpringBootApplication
@AutoConfigurationPackage(basePackages = "org.javaboy.auto_package")
@ComponentScan(basePackages = "org.javaboy.auto_package")
public class AutoPackageApplication {

    public static void main(String[] args) {
        SpringApplication.run(AutoPackageApplication.class, args);
    }

}

此时,项目就可以成功启动了,因为 @AutoConfigurationPackage(basePackages = "org.javaboy.auto_package") 注解可以扫描到 @Mapper 注解。

当然,这里只是为了给大家演示问题,实际场景下直接在启动类上加 @MapperScan(basePackages = "org.javaboy.auto_package") 注解就可以了。因为 @MapperScan 注解是 mybatis-spring 提供的,而 @Mapper 是 MyBatis 自己提供的,两个注解的出处本身就不同。

默认情况下,Spring Boot 项目的启动注解中,实际上已经包含了 @AutoConfigurationPackage 注解,具体位置在 @SpringBootApplication->@EnableAutoConfiguration->@AutoConfigurationPackage,默认该注解没有指定 basePackages 属性,表示使用启动类所在的包作为根包,扫描该包下的所有第三方 Bean,所以我们平时在 Spring Boot 中使用 MyBatis 的时候,是不需要额外加 @AutoConfigurationPackage 注解的。

经过上面问题的演示,相信小伙伴们已经搞明白了 @AutoConfigurationPackage@ComponentScan 的区别了吧?

相关推荐
雷神乐乐15 分钟前
File.separator与File.separatorChar的区别
java·路径分隔符
小刘|19 分钟前
《Java 实现希尔排序:原理剖析与代码详解》
java·算法·排序算法
逊嘘39 分钟前
【Java语言】抽象类与接口
java·开发语言·jvm
morris1311 小时前
【SpringBoot】Xss的常见攻击方式与防御手段
java·spring boot·xss·csp
七星静香1 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员1 小时前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU1 小时前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea
stewie61 小时前
在IDEA中使用Git
java·git
Elaine2023912 小时前
06 网络编程基础
java·网络
G丶AEOM2 小时前
分布式——BASE理论
java·分布式·八股