述
上文中了解了通过 spring.factories
指定系统初始化器的加载原理,最后就是把所有的系统初始化器都创建了实例,然后通过 setInitializers()
方法放到了 SpringApplication
对象中,然后在 SpringApplication.run()
框架启动的时候,会执行集合中的这些系统初始化器,下面看一下具体是如何调用的
相关框架启动流程图
我们的初始化器,都是重写了一个 initialize()
方法,那么这个方法是在哪里被调用的,如下图:
系统初始化器的解析,在刷新上下文之前执行,下面跟踪源码看一下具体实现
源码跟踪
从启动类的run方法一步一步点进去看,如下:
这里先不管其他方法,只看刷新上下文之前的方法,点进去看一下:
点进去这个方法,源码如下:
这里首先通过 getInitializers()
方法,拿到所有的初始化器,然后循环判断,最后调用每个实例的 initialize()
方法
以上就是我们之前的第一种方式实现的系统初始化器的加载和解析原理,我们之前一共使用了三种系统初始化器,那么下面再来看下后面的两种的加载方式
硬编码方式加载原理
第二种系统初始化器的实现,就是在启动类中,添加了一行代码 springApplication.addInitializers(new SecondInitializer());
,这个比较简单,点击 addInitializers
方法,看下源码,如下:
很简单,就是拿到集合然后添加进去就完成了
application 配置文件加载原理
再来看一下最后一种方式, 这里主要用到的一个类,是 DelegatingApplicationContextInitializer
,这个类其实也是一个系统初始化器,也是实现了 ApplicationContextInitializer<ConfigurableApplicationContext>
这个接口
然后这个类,其实是在 Spring Boot 一个jar包中的 spring.factories
中定义的,如下:
所以这个类,也是会被之前说的 SpringFactoriesLoader
去扫描到,然后来看一下这个类的源码
这里要注意的地方是,他实现了order接口,然后定义的order值是0,这也就解释了为什么通过 application.yml
配置的系统初始化器会被先执行
然后上面的代码主要就是从配置的 context.initializer.classes
中,找到所有指定的类,然后创建实例,最后调用 applyInitializerClasses()
方法,代码如下:
这里拿到实例之后,最后循环调用实例的 initialize()
方法
总结
系统初始化器实现的三种方式:
- 定义在
spring.factories
中,被SpringFactoriesLoader
发现注册. - 在
SpringApplication
初始化完毕之后手动添加 - 定义成环境变量,被
DelegatingApplicationContextInitializer
发现注册
作用:
- 在框架启动的过程中,向 Spring Boot 容器中配置一些属性