Springboot启动流程
- 框架初始化
-
- 配置资源加载器
- 配置primarySources
- 应用环境检测
- 配置系统初始化器
- 配置应用监听器
- 配置main方法所在类
- 框架启动
- 自动化装配
初始化器解析
概览
- 类名: ApplicationContextInitializer
- 介绍:Spring容器刷新之前执行的一个回调函数
- 作用: 向Spring Boot容器中注册属性
- 使用: 继承接口自定义实现
实现方式1
- 实现ApplicationContextInitializer接口
- spring.factories内填写接口实现
-
- key值:
org.springframework.context.ApplicationContextInitializer
- value值为自定义初始化器的全类名
- key值:
@Order(1)
public class FirstInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {ConfigurableEnvironment environment = applicationContext.getEnvironment();environment.setRequiredProperties("mooc");
// Map<String, Object> map = new HashMap<>();
// map.put("key1", "value1");
// MapPropertySource mapPropertySource = new MapPropertySource("firstInitializer", map);
// environment.getPropertySources().addLast(mapPropertySource);
// System.out.println("run firstInitializer");}
}
resources/META-INF/spring.factories编写添加:
org.springframework.context.ApplicationContextInitializer=com.mooc.sb2.initializer.FirstInitializer
实现方式2
- 实现ApplicationContextInitializer接口
- 在springApplication类初始后设置进去
@Order(2)
public class SecondInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {ConfigurableEnvironment environment = applicationContext.getEnvironment();Map<String, Object> map = new HashMap<>();map.put("key2", "value2");MapPropertySource mapPropertySource = new MapPropertySource("secondInitializer", map);environment.getPropertySources().addLast(mapPropertySource);System.out.println("run secondInitializer");}
}
设置:
@SpringBootApplication
@MapperScan("com.mooc.sb2.mapper")
public class Sb2Application {public static void main(String[] args) {
// SpringApplication.run(Sb2Application.class, args);SpringApplication springApplication = new SpringApplication(Sb2Application.class);springApplication.addInitializers(new SecondInitializer());springApplication.run(args);}}
实现方式3
- 实现ApplicationContextInitializer接口
- application.properties内填写接口实现
-
- key:
context.initializer.classes
- value值为自定义初始化器的全类名
- key:
@Order(3)
public class ThirdInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {ConfigurableEnvironment environment = applicationContext.getEnvironment();Map<String, Object> map = new HashMap<>();map.put("key3", "value3");MapPropertySource mapPropertySource = new MapPropertySource("thirdInitializer", map);environment.getPropertySources().addLast(mapPropertySource);System.out.println("run thirdInitializer");}
}
context.initializer.classes=com.mooc.sb2.initializer.ThirdInitializer
注意事项
- 都要实现ApplicationContextInitializer接口
- Order值越小越先执行
- applicantion.properties中定义的优先于其他方式
工厂加载机制
SpringFactoriesLoader介绍
- 框架内部使用的通用工厂加载机制
- 从classpath下多个jar包特定的位置读取文件并初始化类
- 文件内容必须是kv形式,即properties类型
- key是全限定名(抽象类 | 接口)、value是实现,多个实现用','分隔
loadFactories流程
源码具体流程:
系统初始化器解析
作用
- 上下文刷新即refresh方法之前调用
- 用来编码设置一些属性变量通常用在web环境中
- 可以通过实现Order接口来进行排序
初始化器总结流程
三种方式:
- 定义在
spring.factories
文件中被SpringFactoriesLoader
发现注册 - SpringApplication初始化完毕后手动添加
- 定义成环境变量被
DelegatingApplicationContextInitializer
发现注册
所以为什么application.properties
中的初始化器不管定义为Order为多少都是最先被加载,因为DelegatingApplicationContextInitializer
中的Order设置的是0, 优先加载的始终是DelegatingApplicationContextInitializer
中的初始化器
最后推荐使用spring.factories
的方式定义初始化器
面试题
- 介绍下SpringFactoriesLoader?
-
- 就是一个SpringBoot的一个工厂加载类, 用它来完成我们扩展点的实现的载入
- SpringFactoriesLoader如何加载工厂类?
-
- 读取指定路径下的指定文件(META/spring.factories文件),将他们读取成一个properties对象,依次遍历我们的文件内容,将其组装成我们的类名以及对应的实现来依次遍历它, 通过Order进行排序
- 系统初始化器的作用?
-
- SpringBoot容器的一个回调接口, 可以通过它以编码形式的定义我们容器中的属性
- 系统初始化器的调用时机?
-
- 是在SpringBoot.run()方法当中的prepareContext()中的applyInitializers()方法中进行调用的
- 如何自定义实现系统初始化器?
-
- 上面三种实现方式
- 自定义实现系统初始化器有哪些注意事项?
-
- 主要是Order值的大小排序问题, 以及不同的实现方式导致Order值失效的问题