SpringBoot初始化

Springboot启动流程

  • 框架初始化
    • 配置资源加载器
    • 配置primarySources
    • 应用环境检测
    • 配置系统初始化器
    • 配置应用监听器
    • 配置main方法所在类

SpringBoot初始化_第1张图片

  • 框架启动

SpringBoot初始化_第2张图片

  • 自动化装配

SpringBoot初始化_第3张图片

初始化器解析

概览

  • 类名: ApplicationContextInitializer
  • 介绍:Spring容器刷新之前执行的一个回调函数
  • 作用: 向Spring Boot容器中注册属性
  • 使用: 继承接口自定义实现

实现方式1

  • 实现ApplicationContextInitializer接口
  • spring.factories内填写接口实现
    • key值: org.springframework.context.ApplicationContextInitializer
    • value值为自定义初始化器的全类名
@Order(1)
public class FirstInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        environment.setRequiredProperties("mooc");
//        Map 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 {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        Map 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值为自定义初始化器的全类名
@Order(3)
public class ThirdInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        Map 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是实现,多个实现用','分隔

SpringBoot初始化_第4张图片

loadFactories流程

SpringBoot初始化_第5张图片

源码具体流程:

SpringBoot初始化_第6张图片

系统初始化器解析

作用

  • 上下文刷新即refresh方法之前调用
  • 用来编码设置一些属性变量通常用在web环境中
  • 可以通过实现Order接口来进行排序

SpringBoot初始化_第7张图片

初始化器总结流程

SpringBoot初始化_第8张图片

三种方式:

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

所以为什么application.properties中的初始化器不管定义为Order为多少都是最先被加载,因为DelegatingApplicationContextInitializer中的Order设置的是0, 优先加载的始终是DelegatingApplicationContextInitializer中的初始化器

最后推荐使用spring.factories的方式定义初始化器

SpringBoot初始化_第9张图片

面试题

  • 介绍下SpringFactoriesLoader?
    • 就是一个SpringBoot的一个工厂加载类, 用它来完成我们扩展点的实现的载入
  • SpringFactoriesLoader如何加载工厂类?
    • 读取指定路径下的指定文件(META/spring.factories文件),将他们读取成一个properties对象,依次遍历我们的文件内容,将其组装成我们的类名以及对应的实现来依次遍历它, 通过Order进行排序
  • 系统初始化器的作用?
    • SpringBoot容器的一个回调接口, 可以通过它以编码形式的定义我们容器中的属性
  • 系统初始化器的调用时机?
    • 是在SpringBoot.run()方法当中的prepareContext()中的applyInitializers()方法中进行调用的
  • 如何自定义实现系统初始化器?
    • 上面三种实现方式
  • 自定义实现系统初始化器有哪些注意事项?
    • 主要是Order值的大小排序问题, 以及不同的实现方式导致Order值失效的问题

你可能感兴趣的:(SpringBoot源码解析,spring,boot,java,后端)