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 举例。