前言
Spring Boot 版本 2.3.4.RELEASE
说了这么久的约定大于配置,今天就来说说Spring Boot 是如何实现约定大于配置的。也就是Spring Boot 的自动装配。
之前的文章感觉有点啰嗦了,从这篇文章开始,博主将尽量言简意赅地讲清楚这些知识点。
什么是自动装配
此处我们以Web 开发为例,在使用Spring Boot 进行开发之后,我们不需要像之前的SSM 一样需要进行各种各样的配置,例如DispatcherServlet、CharacterEncodingFilter等,就能够直接进行业务上的开发。因为Spring Boot 已经帮我们完成了这些配置,者就是自动装配。
@SpringBootApplication
每个使用Spring Boot 的开发者对这个注解应该都不会陌生,这篇文章要讲的自动装配也要从他开始
- 点进该注解,可以看到除了元注解以外,它还有三个子注解组成
- @SpringBootConfiguration 表明当前类是一个配置类
- @EnableAutoConfiguration 开启自动配置,也是自动装配的核心注解
- @ComponentScan 指定扫描包路径和Spring注解
@EnableAutoConfiguration
- 点进该注解,同样可以看到除了元注解以外,它还有二个子注解组成
- @AutoConfigurationPackage 自动装配包,指定包的路径下的组件
- @Import(AutoConfigurationImportSelector.class) 通过导入AutoConfigurationImportSelector 组件,进行批量注册
@AutoConfigurationPackage
这个注解将该项目下的自定义的组件进行装配
- 点进该注解,可以看到@Import(AutoConfigurationPackages.Registrar.class) 它通过导入AutoConfigurationPackages.Registrar.class 来完成了指定包路径下的组件注册。让我们看看它是如何实现的。
这个方法有两个参数:
- AnnotationMetadata metadata 元数据信息,也就是
- BeanDefinitionRegistry registry 当前的bean 注册中心
打断点看一下
这里得到了主类的包名,再进入register 方法,它先判断了一下BEAN 这个组件(AutoConfigurationPackages.class.getName())是否存在,这里是第一次进入,肯定是不存在,于是这里它进行了一些操作,将MainApplication 所在包下组件全部注入IOC。
@Import(AutoConfigurationImportSelector.class)
@EnableAutoConfiguration 的另一个子注解,通过导入AutoConfigurationImportSelector.class来完成自定义以外的组件注册,也就是默认的配置。
AutoConfigurationImportSelector实现了ImportSelector接口,那么我们清楚只需要关注selectImports方法的返回结果。
让我们重点关注一下getAutoConfigurationEntry 方法
查看上面的注释,可以大概知道这个方法的用途:获取应该导入的自动配置
下面让我们分析一下它是如何获取应该导入的自动配置的。
- AnnotationAttributes attributes = getAttributes(annotationMetadata); 这行代码获取了注解上的属性。
- List
configurations = getCandidateConfigurations(annotationMetadata, attributes); 这行代码获取了所有的候选的待加载配置信息。打断点可以看到有很多类的全路径。 - 这些类的全路径又是如何获取到的呢,我们点进这个方法看一下
- 再深入一点,我们可以看到
META-INF/spring.factories
这个路径极为重要,这个方法会加载这个项目下所有jar包下这个路径的spring.factories 这个配置文件,并读取里面的内容- 这里我们看下spring-boot-autoconfigure 的jar包,可以看到里面的内容和断点里得到的结果是 差不多的。
- configurations = removeDuplicates(configurations); 去除重名的。
- Set
exclusions = getExclusions(annotationMetadata, attributes); 获取我们配置的希望不要加载的自动配置类 - configurations.removeAll(exclusions); 去除配置的不需加载的
- configurations = getConfigurationClassFilter().filter(configurations); 过滤掉不需要加载的
- 我们打断点来看看去除同名、去除显式配置的、再过滤之后,需要加载的配置类。
- 还剩26个,这是如何过滤的呢,这就需要讲一下按需配置了。
按需开启自动配置项
此处以BatchAutoConfiguration 为例
可以看到图中有爆红的类,分别是
- @ConditionalOnClass({ JobLauncher.class, DataSource.class })
- @ConditionalOnBean(JobLauncher.class)
这两个注解也就是我们上篇博客说到的@Conditional 注解的派生注解,说明这个配置类只有在IOC容器中有JobLauncher、DataSource这两个类和JobLauncher 才会装配。
而我们这个项目是个Web 项目,我们可以看看web下的配置类会不会被加载。
可以看到,BatchAutoConfiguration 被过滤掉了,而Web 相关的,例如DispatcherServletAutoConfiguration就没有被过滤掉。
绑定配置文件
这些自动配置类中,有一部分的配置信息可以通过配置文件来定义,如
ServletWebServerFactoryAutoConfiguration 绑定了ServerProperties,他会读取配置文件中以server 开头的属性,例如我们经常配置的启动端口port 就是通过这里绑定的。
自动配置以配置文件优先,如果配置文件中没有配置则进行默认的配置。
查看自动配置装配情况
在配置文件中加入配置debug=true
,启动项目,查看控制台
- 已经装配的
- 没装配的,以及为什么没装配
总结
- SpringBoot先加载所有的jar 包下的
META-INF/spring.factories
的所有自动配置类 xxxxxAutoConfiguration - 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
- 生效的配置类就会给容器中装配很多组件
- Spring Boot 启动完成
以上就是Spring Boot的自动装配的大致流程,如果有遗漏和错误的地方,请各位批评指正。
声明
这篇博客基于B站尚硅谷的视频:雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)编写。
在此先表示感谢。
如有侵权,请联系我删除。