SpringBoot-系统初始化器

653 阅读2分钟

系统初始化器介绍

原理

  1. 类名ApplicationContextInitializer
  2. 介绍Spring容器刷新之前执行的回调函数
  3. 向SpringBoot容器中注册属性
  4. 继承接口自定义实现

实现方式

方法一

1.创建FirstInitializer类实现ApplicationContextInitializer接口

@Order(1)
public class FirstInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();
        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");
    }
}

2.resource下创建META-INF/spring.factories文件,配置属性

org.springframework.context.ApplicationContextInitializer=com.example.demo.initializer.FirstInitializer

方法二

  1. 创建SecondInitializer类实现ApplicationContextInitializer接口
@Order(2)
public class SecondInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        ConfigurableEnvironment environment = configurableApplicationContext.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");
    }
}
  1. 启动类里,手动添加初始化示例
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {      
        SpringApplication application = new  SpringApplication(DemoApplication.class);
        application.addInitializers(new SecondInitializer());
        application.run(args);
    }

}

方法三

  1. 创建ThirdInitializer类实现ApplicationContextInitializer接口
@Order(3)
public class ThirdInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        ConfigurableEnvironment environment = configurableApplicationContext.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");
    }
}
  1. 在resource下的application.properties里添加配置
context.initializer.classes=com.example.demo.initializer.ThirdInitializer

tips:application.properties里配置,是DelegatingApplicationContextInitializer实现读取初始化配置的方法,该方法order=0,所以第一个执行该初始化

注意

  1. 都要是实现ApplicationContextInitializer接口
  2. Order值越小越先执行
  3. application.properties中定义的优先于其他方式

SpringFactoriesLoader介绍

原理

  1. 框架内部使用的通用工厂加载机制
  2. 从classpath下多个jar包特定的位置读取文件并初始化类
  3. 文件内容必须是kv形式,即properties类型
  4. key是全限定名(抽象类|接口)、value是实现,多个实现用,分割

框架初始化步骤

SpringFactoriesLoader作用

SpringBoot框架中从类路径jar包中读取特定文件实现扩展类的载入

loadFactoies流程

系统初始化器原理解析

作用

  1. 上下文刷新即refresh方法前调用
  2. 用来编码设置一些属性变量通常用在web环境中
  3. 可以通过order接口进行排序

调用点

调用流程

实现原理

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

面试题

介绍下SpringFactoriesLoader?

SpringBoot工厂的加载类, SpringBoot用它完成扩展点的载入

SpringFactoriesLoader如何加载工厂类?

读取指定路径下的指定文件,把他们读取成property对象,依次遍历文件内容,组装成类名和对应的实现,通过order进行排序。

系统初始化器的作用?

他其实是SpringBoot容器的一个回调接口,我们可以向SpringBoot容器定义我们的属性。

系统初始化器调用时机?

在springboot启动过程中的prepareContext过程中调用