Spring Boot-2-系统初始化器解析原理

上文中了解了通过 spring.factories 指定系统初始化器的加载原理,最后就是把所有的系统初始化器都创建了实例,然后通过 setInitializers() 方法放到了 SpringApplication 对象中,然后在 SpringApplication.run() 框架启动的时候,会执行集合中的这些系统初始化器,下面看一下具体是如何调用的

相关框架启动流程图

我们的初始化器,都是重写了一个 initialize() 方法,那么这个方法是在哪里被调用的,如下图:
image

系统初始化器的解析,在刷新上下文之前执行,下面跟踪源码看一下具体实现

源码跟踪

从启动类的run方法一步一步点进去看,如下:

image

这里先不管其他方法,只看刷新上下文之前的方法,点进去看一下:

image

点进去这个方法,源码如下:

image

这里首先通过 getInitializers() 方法,拿到所有的初始化器,然后循环判断,最后调用每个实例的 initialize() 方法

以上就是我们之前的第一种方式实现的系统初始化器的加载和解析原理,我们之前一共使用了三种系统初始化器,那么下面再来看下后面的两种的加载方式

硬编码方式加载原理

第二种系统初始化器的实现,就是在启动类中,添加了一行代码 springApplication.addInitializers(new SecondInitializer()); ,这个比较简单,点击 addInitializers 方法,看下源码,如下:

image

很简单,就是拿到集合然后添加进去就完成了

application 配置文件加载原理

再来看一下最后一种方式, 这里主要用到的一个类,是 DelegatingApplicationContextInitializer ,这个类其实也是一个系统初始化器,也是实现了 ApplicationContextInitializer<ConfigurableApplicationContext> 这个接口

然后这个类,其实是在 Spring Boot 一个jar包中的 spring.factories 中定义的,如下:

image

所以这个类,也是会被之前说的 SpringFactoriesLoader 去扫描到,然后来看一下这个类的源码

image

这里要注意的地方是,他实现了order接口,然后定义的order值是0,这也就解释了为什么通过 application.yml 配置的系统初始化器会被先执行
然后上面的代码主要就是从配置的 context.initializer.classes 中,找到所有指定的类,然后创建实例,最后调用 applyInitializerClasses() 方法,代码如下:

image

这里拿到实例之后,最后循环调用实例的 initialize() 方法

总结

系统初始化器实现的三种方式:

  • 定义在 spring.factories 中,被 SpringFactoriesLoader 发现注册.
  • SpringApplication 初始化完毕之后手动添加
  • 定义成环境变量,被 DelegatingApplicationContextInitializer 发现注册

作用:

  • 在框架启动的过程中,向 Spring Boot 容器中配置一些属性