在hello world程序中可以看到,因为有@SpringBootApplication注解所以我们什么都不需要写就可以拥有web开发能力,那么这背后的原理是什么,SpringBoot的自动配置功能如何实现的?

  1. @SpringBootApplication
  2. public class SpringbootdemoApplication {
  3. public static void main(String[] args) {
  4. SpringApplication.run(SpringbootdemoApplication.class, args);
  5. }
  6. }

1.@SpringBootApplication注解的组成

点进去可以发现此注解由三个注解组成,其中@SpringBootConfiguration注解表示被标注的类是一个配置类,@ComponentScan负责将指定的类注册到容器中,因此提供了自动配置功能的是@EnableAutoConfiguration。
image.png

  1. @Configuration
  2. public @interface SpringBootConfiguration {

进入@EnableAutoConfiguration注解,可以发现它是由两个注解组成的

  1. @AutoConfigurationPackage
  2. @Import(AutoConfigurationImportSelector.class)
  3. public @interface EnableAutoConfiguration {

@AutoConfigurationPackage

查看此注解发现它使用@Import注解导入了一个类:AutoConfigurationPackages.Registrar.class

  1. @Import(AutoConfigurationPackages.Registrar.class)
  2. public @interface AutoConfigurationPackage {

进入此类后发现它重写了两个方法
image.png
它会调用registerBeanDefinitions方法注册组件,在此方法上打上断点后启动容器,执行register方法,此时它会判断容器中是否存在AutoConfigurationPackage类,如果不存在则将其注入到容器中,因此自动配置功能不是这个注解提供的。
image.png

2.获取配置类的过程

@Import(AutoConfigurationImportSelector.class)

排除掉上一个注解后只剩下导入的这个类了,因此该类肯定提供了自动配置功能,在代码中可以看到,在调用了getAutoConfigurationEntry方法后会返回很多个XXXConfiguration
image.png
这些返回的配置就是目前项目中已经生效的自动配置,因此核心内容就在于getAutoConfigurationEntry方法是如何实现的了

getAutoConfigurationEntry方法

进入该方法并加上断点后会发现,当运行了getCandidateConfigurations方法后就会获取到很多个XXXConfiguration,后面的代码就是根据配置过滤需要生效的自动配置了,那么现在的核心转移到了getCandidateConfigurations方法
image.png

getCandidateConfigurations方法

进入该方法后发现参数autoConfigurationMetadata中已经包含了所有的自动配置类,因此核心方法应该在参数的传递上,本方法主要的作用是过滤不符合要求的自动配置,最后返回需要激活的配置类
image.png

getAutoConfigurationMetadata方法

返回查看process方法后发现获取参数的方法为getAutoConfigurationMetadata,进入此方法发现它调用了loadMetadata方法
image.png
在loadMetadata方法中它传递了一个值为META-INF/spring-autoconfigure-metadata.properties的路径
image.png
image.png
打开该文件发现它定义了许多的键值对,并且除去第一行注释后它的行数和我们获取的到数据总数是一样的
image.png
image.png
最后经过重重过滤后返回的就是需要生效的配置类了

3.XXXAutoConfiguration原理

到目前为止已经知道了SpringBoot通过AutoConfigurationImportSelector类获取到了spring-autoconfigure-metadata.properties文件中的所有键值对,并对这些数据进行了过滤,那么它需要这些字符串有什么用呢
本次讲解常用的WebMvcAutoConfiguration类具体做了什么,其他的XXXAutoConfiguration原理基本类似
根据该类上加的注解可以看到执行此类需要满足的条件,其中Conditional*表示只有当容器中满足某个条件时才加载该配置类
image.png
里面主要的代码就是满足条件后向容器中注册bean,或者是内置的配置类
image.png
我们以WebMvcAutoConfigurationAdapter类为例进行研究

  1. @Configuration(proxyBeanMethods = false)
  2. @Import(EnableWebMvcConfiguration.class)
  3. @EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
  4. @Order(0)
  5. public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {

它使用@EnableConfigurationProperties注解导入了WebMvcProperties.class, ResourceProperties.class两个类,该注解的含义是将properties或yml配置文件中的属性和对应的Properties类中的字段绑定
image.png
比如WebMvcProperties类中用@ConfigurationProperties(prefix = “spring.mvc”)标注了它的前缀,而此类中存在dateFormat属性,因此我们可以在配置文件中配置如下信息

  1. spring.mvc.date-format=yyyy-mm-dd

此处列出的所有值都在WebMvcProperties中存在对应的属性,并且已经有默认值了
image.png
可以看到在向容器中注入时就会使用我们配置好的值了,其他没有配置的属性则是使用默认值
image.png

4.总结

简单概况下自动配置原理:

  1. 读取spring-autoconfigure-metadata.properties获取所有自动配置类
  2. 根据是否引入对应的starter判断自动配置类是否生效
  3. 每个自动配置类对应一个或多个Properties类,其中该类中存在使用starter时需要的所有默认配置
  4. 我们可以在配置文件中覆盖掉默认值

因此SpringBoot的自动配置原理是它在内部帮我们写好了所有可能要用到的配置项,当满足一定条件后就加载对应的配置类,因此我们可以开箱即用,如果它提供的功能还不能满足你的需求,你还可以自定义starter