本博客源码地址
https://github.com/suchahaerkang/spring-boot-study.git
ApplicationContextInitializer 是在spring容器刷新之前执行的一个回调函数。它的作用是向springboot容器中注册属性
将ApplicationContextInitializer的实现类注册到容器中有三种方式:
1)在spring.factories内配置ApplicationContextInitializer的实现类的方式来注册
首先自己写一个ApplicationContextInitializer的实现类
/**
* @description:
* @author: sukang
* @date: 2020-03-22 20:34
*/
@Order(1)
public class FirstInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
//从容器中获取环境变量组件
ConfigurableEnvironment environment = applicationContext.getEnvironment();
//自己自定义一些属性放在map集合中
Map<String, Object> map = new HashMap<>();
map.put("key1", "value1");
//包装为MapPropertySource组件
MapPropertySource mapPropertySource = new MapPropertySource("firstInitializer", map);
//存到环境变量中去
environment.getPropertySources().addLast(mapPropertySource);
System.out.println("FirstInitializer属性注册成功...");
}
}
然后在src/main/resources目录下新建/META-INF/spring.factories,将FirstInitializer组件的类路径配置进去
在UserService中写一个方法来获取环境变量中key为key1的value值
在UserController中写一个方法调用UserService的getInitializerValue()方法
启动项目测试结果如下
2)自己手动注册
重新再自定义一个初始化器
/**
* @description:
* @author: sukang
* @date: 2020-03-22 20:34
*/
@Order(2)
public class SecondInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
//从容器中获取环境变量组件
ConfigurableEnvironment environment = applicationContext.getEnvironment();
//自己自定义一些属性放在map集合中
Map<String, Object> map = new HashMap<>();
map.put("key2", "value2");
//包装为MapPropertySource组件
MapPropertySource mapPropertySource = new MapPropertySource("secondInitializer", map);
//存到环境变量中去
environment.getPropertySources().addLast(mapPropertySource);
System.out.println("SecondInitializer属性注册成功...");
}
}
手动注册初始化器
@SpringBootApplication
@MapperScan("com.wolfx.springbootstudy.dao")
public class SpringBootStudyApplication {
public static void main(String[] args) {
//SpringApplication.run(SpringBootStudyApplication.class, args);
SpringApplication springApplication = new SpringApplication(SpringBootStudyApplication.class);
//手动注册初始化器
springApplication.addInitializers(new SecondInitializer());
springApplication.run(args);
}
}
Controller和Service文件
运行结果
3)在application.properties文件中进行配置
首先我们再自定义一个初始化器
/**
* @description:
* @author: sukang
* @date: 2020-03-22 20:34
*/
@Order(3)
public class ThirdInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
//从容器中获取环境变量组件
ConfigurableEnvironment environment = applicationContext.getEnvironment();
//自己自定义一些属性放在map集合中
Map<String, Object> map = new HashMap<>();
map.put("key3", "value3");
//包装为MapPropertySource组件
MapPropertySource mapPropertySource = new MapPropertySource("thirdInitializer", map);
//存到环境变量中去
environment.getPropertySources().addLast(mapPropertySource);
System.out.println("ThirdInitializer属性注册成功...");
}
}
然后在application.properties文件中进行配置将ThirdInitializer注册到容器中去
#initializer
context.initializer.classes=com.wolfx.springbootstudy.initializer.ThirdInitializer
Controller和Service文件
测试结果
以上的结果说明这三种方式都成功的将初始化器注册到了容器中了。上面我们编写三个初始化实现类FirstInitializer,SecondInitializer和ThirdInitializer的order值分别是1,2,3 ,按理说应该是按照这个顺序回调他们重写的initialize()方法,但是在控制台中打印的结果和我们想象的不一样
下面我们带着这个问题来看源码,看一下ApplicationContextInitializer回调方法的执行时机
我们以创建SpringApplication为入口
进入getSpringFactoriesInstances()方法
我们看一下SpringFactoriesLoader组件的作用
我们进入loadSpringFactories()方法
前面我们知道ApplicationContextInitializer是在容器刷新之前回调其方法实现自定义一些属性值,那么我们从SpringApplication.run()方法进去看一下源码
在此我们已经清楚了通过SpringFactoriesLoader和手动注册的初始化器是怎么注册的已经怎么回调他们的方法的,但是我们还是不知道
ThirdInitializer为啥Order为3,但是第一个执行回调方法,其实他是通过DelegatingApplicationContextInitializer这个组件实现的。DelegatingApplicationContextInitializer组件也是ApplicationContextInitializer的一个实现类并且order为0
DelegatingApplicationContextInitializer配置在spring.factories中,所以会被SpringFactoriesLoader读取注册到容器中去,等执行run()方法的
时候,首先回调的是DelegatingApplicationContextInitializer的initialize()方法,因为它的order为0,所以最优先执行
执行DelegatingApplicationContextInitializer.initialize(ConfigurableApplicationContext context)方法
总结一下初始化器的实现类initialize()方法的回调流程
总结一下实现方式
一般推荐使用第一种方式
1)介绍一下SpringFactoriesLoader?
SpringFactoriesLoader其实就是spring的工厂加载类,作用是完成扩展点的实现载入
2)SpringFactoriesLoader是如何加载工厂类的?
通过读取/META-INF/spring.factories文件,将其转为Property对象,然后获取遍历value值,得到相应的类路径名,并且根据Order排序
3)系统初始化器的作用?
它其实就是spring容器的一个回调接口,在容器刷新之前执行,主要作用是给可以自定义一些属性值