前言

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 来完成了指定包路径下的组件注册。让我们看看它是如何实现的。

image.png
这个方法有两个参数:

  • AnnotationMetadata metadata 元数据信息,也就是
  • BeanDefinitionRegistry registry 当前的bean 注册中心

打断点看一下
image.png
这里得到了主类的包名,再进入register 方法,它先判断了一下BEAN 这个组件(AutoConfigurationPackages.class.getName())是否存在,这里是第一次进入,肯定是不存在,于是这里它进行了一些操作,将MainApplication 所在包下组件全部注入IOC。
image.png

@Import(AutoConfigurationImportSelector.class)

@EnableAutoConfiguration 的另一个子注解,通过导入AutoConfigurationImportSelector.class来完成自定义以外的组件注册,也就是默认的配置。

AutoConfigurationImportSelector实现了ImportSelector接口,那么我们清楚只需要关注selectImports方法的返回结果。

image.png

让我们重点关注一下getAutoConfigurationEntry 方法

image.png
查看上面的注释,可以大概知道这个方法的用途:获取应该导入的自动配置
下面让我们分析一下它是如何获取应该导入的自动配置的。

  1. AnnotationAttributes attributes = getAttributes(annotationMetadata); 这行代码获取了注解上的属性。
  2. List configurations = getCandidateConfigurations(annotationMetadata, attributes); 这行代码获取了所有的候选的待加载配置信息。打断点可以看到有很多类的全路径。
  3. image.png
  4. 这些类的全路径又是如何获取到的呢,我们点进这个方法看一下
  5. image.png
  6. 再深入一点,我们可以看到image.png
  7. image.png
  8. META-INF/spring.factories这个路径极为重要,这个方法会加载这个项目下所有jar包下这个路径的spring.factories 这个配置文件,并读取里面的内容
  9. 这里我们看下spring-boot-autoconfigure 的jar包,可以看到里面的内容和断点里得到的结果是 差不多的。
  10. image.pngimage.png
  11. configurations = removeDuplicates(configurations); 去除重名的。
  12. Set exclusions = getExclusions(annotationMetadata, attributes); 获取我们配置的希望不要加载的自动配置类
  13. configurations.removeAll(exclusions); 去除配置的不需加载的
  14. configurations = getConfigurationClassFilter().filter(configurations); 过滤掉不需要加载的
  15. 我们打断点来看看去除同名、去除显式配置的、再过滤之后,需要加载的配置类。
  16. image.png
  17. 还剩26个,这是如何过滤的呢,这就需要讲一下按需配置了。

按需开启自动配置项

此处以BatchAutoConfiguration 为例
image.png
可以看到图中有爆红的类,分别是

  • @ConditionalOnClass({ JobLauncher.class, DataSource.class })
  • @ConditionalOnBean(JobLauncher.class)
    这两个注解也就是我们上篇博客说到的@Conditional 注解的派生注解,说明这个配置类只有在IOC容器中有JobLauncher、DataSource这两个类和JobLauncher 才会装配。

而我们这个项目是个Web 项目,我们可以看看web下的配置类会不会被加载。
下载.png
可以看到,BatchAutoConfiguration 被过滤掉了,而Web 相关的,例如DispatcherServletAutoConfiguration就没有被过滤掉。
image.png

绑定配置文件

这些自动配置类中,有一部分的配置信息可以通过配置文件来定义,如
image.png

ServletWebServerFactoryAutoConfiguration 绑定了ServerProperties,他会读取配置文件中以server 开头的属性,例如我们经常配置的启动端口port 就是通过这里绑定的。
image.png

自动配置以配置文件优先,如果配置文件中没有配置则进行默认的配置。

查看自动配置装配情况

在配置文件中加入配置debug=true,启动项目,查看控制台

  • 已经装配的
    image.png
  • 没装配的,以及为什么没装配
    image.png

总结

  • SpringBoot先加载所有的jar 包下的META-INF/spring.factories的所有自动配置类 xxxxxAutoConfiguration
  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
  • 生效的配置类就会给容器中装配很多组件
  • Spring Boot 启动完成

以上就是Spring Boot的自动装配的大致流程,如果有遗漏和错误的地方,请各位批评指正。

声明

这篇博客基于B站尚硅谷的视频:雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)编写。
在此先表示感谢。
如有侵权,请联系我删除。