Spring/SpringBoot系列之SpringBoot 自动配置原理【十】

阅读本文前,最好先阅读:Spring/SpringBoot系列之SpringBoot 源码常用注解【九】

1. SpringBoot 启动过程

在SpringBoot源码中以下四个接口的子类的方法经常被调用:

  • ApplicationContextInitializer
  • ApplicationRunner
  • CommandLineRunner
  • SpringApplicationRunListener

下面开始分析源码,先从 SpringBoot 的启动类的 run() 方法开始看,以下是调用链:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
SpringApplication(primarySources)).run(args)分为两步:

  1. 创建 SpringApplication 对象
  2. 运行 run() 方法

1.1 创建 SpringApplication 对象

在这里插入图片描述

  1. 保存主配置类(这里是一个数组,说明可以有多个主配置类)
  2. 判断是否是一个 Web 应用
  3. 从类路径下找到 META-INF/Spring.factories 配置的所有 ApplicationContextInitializer,然后保存起来
  4. 从类路径下找到 META-INF/Spring.factories 配置的所有 ApplicationListener,然后保存起来
  5. 从多个配置类中找到有 main 方法的主配置类(只有一个)

比如spring-boot-2.2.5.RELEASE.jar下META-INF/Spring.factories内容如下
在这里插入图片描述

1.2 运行 run() 方法

在这里插入图片描述

  1. 创建计时器
  2. 声明 IOC 容器
  3. 从类路径下找到 META/INF/Spring.factories 获取 SpringApplicationRunListeners
  4. 回调所有 SpringApplicationRunListeners 的 starting() 方法
  5. 封装命令行参数
  6. 准备环境,包括创建环境,创建环境完成后回调 SpringApplicationRunListeners#environmentPrepared()方法,表示环境准备完成 在这里插入图片描述
  7. 打印 Banner
  8. 创建 IOC 容器(决定创建 web 的 IOC 容器还是普通的 IOC 容器)
  9. 准备上下文环境,将 environment 保存到 IOC 容器中,并且调用 applyInitializers() 方法。applyInitializers() 方法回调之前保存的所有的 ApplicationContextInitializer 的 initialize() 方法;然后回调所有的 SpringApplicationRunListener#contextPrepared() 方法 ;最后回调所有的 SpringApplicationRunListener#contextLoaded() 方法
  10. 刷新容器,IOC 容器初始化(如果是 Web 应用还会创建嵌入式的 Tomcat),扫描、创建、加载所有组件的地方
  11. 从 IOC 容器中获取所有的 ApplicationRunner 和 CommandLineRunner 进行回调
  12. 调用 所有 SpringApplicationRunListeners#started()方法

run() 阶段主要就是回调本节开头提到过的4种监听器中的方法与加载项目中组件到 IOC 容器中,而所有需要回调的监听器都是从类路径下的 META-INF/Spring.factories 中获取,从而达到启动前后的各种定制操作。

2. SpringBoot 自动配置原理

2.1 @SpringBootApplication

SpringBoot 项目的一切都要从 @SpringBootApplication 这个注解开始说起。

@SpringBootApplication 标注在某个类上,说明:

  • 这个类是 SpringBoot 的主配置类。
  • 运行这个类的 main 方法来启动 SpringBoot 应用。

该注解的定义如下:在这里插入图片描述
可以看到 SpringBootApplication 注解是一个组合注解,其主要组合了三个注解:

  • @SpringBootConfiguration:该注解表示这是一个 SpringBoot 的配置类,其实它就是一个 @Configuration 注解而已。
  • @ComponentScan:开启组件扫描。
  • @EnableAutoConfiguration:从名字就可以看出来,就是这个类开启自动配置的。

2.2 @EnableAutoConfiguration

注解定义:
在这里插入图片描述

2.2.1 @AutoConfigurationPackage

从字面意思理解就是自动配置包。点进去可以看到就是一个 @Import 注解:@Import({Registrar.class}),导入了一个 Registrar 的组件。
在这里插入图片描述
在 Registrar 类中的 registerBeanDefinitions 方法上打上断点,启动项目后可以看到返回了一个包名,该包名其实就是主配置类所在的包:
在这里插入图片描述
总结:

@AutoConfigurationPackage 注解就是将主配置类的所在包及下面所有子包里面的所有组件扫描到Spring容器中。所以说,默认情况下主配置类包及子包以外的组件,Spring 容器是扫描不到的。

2.2.2 @Import({AutoConfigurationImportSelector.class})

该注解给当前配置类导入另外的 N 个自动配置类。

配置类导入规则

AutoConfigurationImportSelector 的 selectImports()方法 就是用来返回需要导入的组件的全类名数组的。得到全类名数组的调用链:getAutoConfigurationEntry() -> getCandidateConfigurations() -> loadFactoryNames():
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
loadFactoryNames() 方法传入了 EnableAutoConfiguration.class 这个参数。
在这里插入图片描述
loadFactoryNames() 中关键的三步:

  1. 从当前项目的类路径中获取所有 META-INF/spring.factories 文件下的信息。
  2. 将上面获取到的文件中的信息封装成一个 Map 返回
  3. 从返回的 Map 中通过刚才传入的 EnableAutoConfiguration.class 参数,获取所有值。
    在这里插入图片描述

META-INF/spring.factories

在很多第三方依赖中都会有这个文件,一般每导入一个第三方的依赖,除了本身的jar包以外,还会有一个 xxx-spring-boot-autoConfigure,这个就是第三方依赖自己编写的自动配置类。以 spring-boot-autocongigure 这个依赖来说:
在这里插入图片描述
可以看到 EnableAutoConfiguration 下面有很多类,这些就是我们项目进行自动配置的类。

总结:

将类路径下 META-INF/spring.factories 里面配置的所有 EnableAutoConfiguration 的值加入到 Spring 容器中。而这些bean依赖条件注解进行自动装配

HttpEncodingAutoConfiguration:

这么多的自动配置类,明显有很多是平常没有使用到的。以 比较简单典型的配置类HttpEncodingAutoConfiguration为例来看一个自动配置类是怎么工作的:
在这里插入图片描述

  1. @Configuration:标记为配置类。
  2. @EnableConfigurationProperties({HttpProperties.class}):启动指定类的ConfigurationProperties功能;将配置文件中对应的值和 HttpProperties 绑定起来;并把 HttpProperties 加入到 IOC 容器中。
  3. @ConditionalOnWebApplication:web应用下才生效
  4. @ConditionalOnClass:指定的类存在才生效
  5. @ConditionalOnProperty:主配置文件中存在指定的属性才生效

因为 @EnableConfigurationProperties({HttpProperties.class})把配置文件中的配置项与 HttpProperties 类绑定上了。

然后在 HttpEncodingAutoConfiguration 中又引用了 HttpProperties ,所以最后就能在 HttpEncodingAutoConfiguration 中使用配置文件中的值了。

最终通过 @Bean 和一些条件判断往容器中添加组件,实现自动配置。(该Bean中属性值是从 HttpProperties 中获取)

HttpProperties

HttpProperties 通过 @ConfigurationProperties 注解将配置文件与自身属性绑定。

在这里插入图片描述

所有在配置文件中能配置的属性都是在 xxxProperties 类中封装着;配置文件能配置什么就可以参照某个功能对应的这个属性类。

3. 总结

  • SpringBoot启动会加载大量的自动配置类。
  • 看看SpringBoot提供的自动配置类是否有我们需要的功能。
  • 再来看这个自动配置类中到底配置了那些组件(只要有我们要用的组件,就不需要再配置)。
  • 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性,然后可以在配置文件中指定这些属性的值。xxxAutoConfiguration:自动配置类给容器中添加组件;xxxProperties:封装配置文件中相关属性。

很多需要待加载的类都放在类路径下的META-INF/Spring.factories 文件下,而不是直接写死在代码中,这样做就可以很方便我们自己或者是第三方去扩展,我们也可以实现自己 starter,让SpringBoot 去加载。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值