SpringBoot 的自动配置原理
SpringBoot 的自动配置原理
课程在讲解 SpringBoot 的自动配置原理时,@ComponentScan 中默认的两个过滤器没有深入讲解,@AutoConfigurationPackage 的作用讲解得有问题,因此这里做一个扩展和订正。
@ComponentScan 中的两个过滤器有什么用?
@SpringBootApplication 注解是 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan 三个注解的组合/合成注解,如下:
1 |
|
注意到 @ComponentScan 没有为 basePackages 属性提供值,此时会默认扫描该注解所标注的类所在的包及其子包下的所有 @Component @Controller @Service @Repository 注解所标注的类。
可以看到 @ComponentScan 的 excludeFilters 还提供了两个过滤器,满足过滤器条件的将会被排出扫描:
TypeExcludeFilter:用于排除特定类型的组件,默认情况下会排除BeanFactory类。
BeanFactory 是 Spring 框架中用于管理 Bean 的核心接口,通常不希望将其作为普通的 Bean 注册到容器中。
AutoConfigurationExcludeFilter:用于排除自动配置类。
@SpringBootApplication 中没有为 @ComponentScan 提供 basePackages 属性,因此是排除主程序所在的包及其子包下的所有自动配置类。
- 什么是自动配置类?
使用 @Configuration 注解标注的类是一个配置类,如果该配置类,还在类路径下的 META-INF/spring.factories 文件中,进行了注册,那么该配置类就是一个自动配置类。
具体怎么注册,其实就是将该配置类的类名放在 org.springframework.boot.autoconfigure.EnableAutoConfiguration 这个键的后面,比如 spring-boot-autoconfigure-2.3.4.RELEASE.jar 包下的 META-INF/spring.factories 就注册了以下配置类为自动配置类:
1 | # Auto Configure |
我们想要定义一个自动配置类的话,假设该类的全类名为 com.atguigu.boot.MyAutoConfiguration,那么首先该类要用 @Configuration 进行标注,然后要在 resources 目录下创建 META-INF/spring.factories 文件,并将该类的全类名进行注册:
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ |
自动配置类的命名一般格式为 XxxxAutoConfiguration。
当一个类是自动配置类的时候,那么在 SpringBoot 启动时,会调用 SpringFactoriesLoader 去读取类路径下,包括依赖 jar 包下,所有 META-INF/spring.factories 文件中的信息,将信息封装到一个 Map<String, List<String>> 中。
比如,META-INF/spring.factories 文件中的自动配置类信息就会以 org.springframework.boot.autoconfigure.EnableAutoConfiguration 为 key,以下面所有注册的自动配置类的全类名为 value,填入 Map 集合中。
- 为什么要排除自动配置类?
一般来说,@SpringBootApplication 包含的三个注解中,@ComponentScan 注解早于 @EnableAutoConfiguration 执行,在 @EnableAutoConfiguration 内部又包含两个注解:
1 |
|
其中 @Import(AutoConfigurationImportSelector.class) 负责将自动配置类导入/注册到容器中。
因此,我们在 @ComponentScan 执行时,就应该将自动配置类的注册工作让出来,讲给后续 @EnableAutoConfiguration 执行时,底层的 @Import(AutoConfigurationImportSelector.class) 来完成。
@AutoConfigurationPackage 底层做了什么,到底有什么用,其功能是否和 @ComponentScan 有重叠?
- 先来看
@AutoConfigurationPackage底层做了什么
1 |
|
其实 @AutoConfigurationPackage 底层做的工作很简单,就是检查当前容器的 BeanDefinitionRegistry 中是否已经注册了名字为 org.springframework.boot.autoconfigure.AutoConfigurationPackages 的 Bean 定义。
如果没有,一般来说启动时是没有注册的,此时就进行注册。
这个要注册 Bean 定义的类型为 AutoConfigurationPackages.BasePackages,其内部就是封装了一个包路径数组,在这里,BasePackages 内部数组只包含一个路径 com.atguigu.boot,就是主程序所在的包。
可以说,@AutoConfigurationPackage 底层相当于是将 com.atguigu.boot 标记为一个自动配置包。
- 所以这有什么用呢?
自动配置类在执行时,可能利用 BasePackages 中的自动配置包路径,来完成组件的注册之类的工作。
比如说,我们在自己应用中使用了 JPA 技术,com.atguigu.boot 包下存在一些用 @Entity 标注的 JPA 的实体类。
此时 JPA 相关的自动配置类,通过 BasePackages 中的自动配置包路径 com.atguigu.boot,就可以找到这些用 @Entity 标注的实体类,并将这些实体类注册到 Spring 中。
同理,如果我们使用了 MybatisPlus 技术,那么 MybatisPlus 相关的自动配置类,就可以找到 com.atguigu.boot 包下的所有 @Mapper 标注的 Mapper 接口,并将这些接口的代理注册到 Spring 中。
@AutoConfigurationPackage功能是否和@ComponentScan有重叠?
@AutoConfigurationPackage 是将自动配置包路径绑定到 Spring 中,方便后续自动配置类扫描这些路径,并注册这些路径中的组件,这些组件一般来说都是用 @Component @Controller @Service @Repository 以外的注解来进行标注的。
@ComponentScan 是扫描指定包下,所有用 @Component @Controller @Service @Repository 注解标注的组件。
可以说,它们的效果有些类似,但它们的注册的对象是不同的!
参考博客
- 一文搞懂🔥SpringBoot自动配置原理:对
@AutoConfigurationPackage的作用的讲解同样有问题,其他地方都不错。 淘宝一面:“说一下 Spring Boot 自动装配原理呗?”:
- 对
@AutoConfigurationPackage的作用的讲解同样有问题 - 提到了对所有候选的自动配置类,是在哪里按条件装配来过滤的。
1
configurations = getConfigurationClassFilter().filter(configurations);
- 提到了如何实现一个 Starter
- 对
SpringBoot自动配置原理:对
AutoConfigurationPackage的作用的讲解基本正确,用 JPA 举例。- SpringBoot源码之-关于注解
@AutoConfigurationPackage作用:对AutoConfigurationPackage的作用的讲解基本正确,用 JPA 举例。 - @AutoConfigurationPackage和@ComponentScan的作用是否冲突?:对
AutoConfigurationPackage的作用的讲解基本正确,用 Mybatis-Plus 举例。