springboot 上下文初始化器在准备上下文阶段会进行调用配置的初始化器进行初始化操作。和自定义ApplicationListener监听器一样。
(一)首先我们来自定义一个自己的初始化器:
public class MyAppContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("MyAppContextInitializer start");
}
}
定义初始化器很简单只需要实现ApplicationContextInitializer<ConfigurableApplicationContext>接口,重写它的initialize方法即可。定义好后我们需要让spring boot启动时加载我们的初始化器,这里有两种常规的做法:
(1)在spring.factories配置
(2)在spring配置文件中配置context.initializer.class参数
我们启动一下,看一下效果,初始化器完美执行:
(二)源码分析
我们来看看源码,深究一下初始化器是什么时候,怎么执行的
(1)启动的入口是SpringApplication.run静态方法,然后会实例化一个SpringApplication实例,在构造方法中会根据spring.factories中定义的初始化器类通过反射获取实例,具体可查看我的另一篇文章《spring-boot启动源码分析(一)之SpringApplication实例构造》。
这里获取的初始化器只有在spring.factories定义的才能获取到,也就是我们的第一种配置方式。第二种方式我们后面随着源码深入,很快就会涉及,别急哦。
(2)构造器只是实例化了初始化器,但并没有直接调用执行初始化方法。实际执行是在prepareContext初始化准备阶段:
applyInitializers方法名称就很明确告诉我们去调用初始化器了。我们接着往下看:
通过遍历我们在SpringApplication构造方法中获取的初始化器,依次调用初始化器的initialize方法,这样初始化器的执行就完成了。到了这里,大家可能就会疑惑:这里初始化器都是从spring.factories中定义的才会执行,那我们通过context.initializer.classes应用变量配置的初始化器怎么执行呢。实际上spring-boot定义了一个DelegatingApplicationContextInitializer代理上下文初始化器,就是代理我们这种方式配置的初始化器的
(3)DelegatingApplicationContextInitializer初始化
我们看到代理类通过从environment中获取context.initializer.classes配置信息,就可以获取到对应的类对象,之后调用applyInitializerClasses(context, initializerClasses);
这里主要就是上下文初始化类实例化对象,然后遍历调用初始化器。到这里我们的上下文初始化的源码就分析完了^_^!