• SpringBoot初始化


    Springboot启动流程

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

    • 框架启动

    • 自动化装配

    初始化器解析

    概览

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

    实现方式1

    • 实现ApplicationContextInitializer接口
    • spring.factories内填写接口实现
      • key值: org.springframework.context.ApplicationContextInitializer
      • value值为自定义初始化器的全类名
    1. @Order(1)
    2. public class FirstInitializer implements ApplicationContextInitializer {
    3. @Override
    4. public void initialize(ConfigurableApplicationContext applicationContext) {
    5. ConfigurableEnvironment environment = applicationContext.getEnvironment();
    6. environment.setRequiredProperties("mooc");
    7. // Map map = new HashMap<>();
    8. // map.put("key1", "value1");
    9. // MapPropertySource mapPropertySource = new MapPropertySource("firstInitializer", map);
    10. // environment.getPropertySources().addLast(mapPropertySource);
    11. // System.out.println("run firstInitializer");
    12. }
    13. }

    resources/META-INF/spring.factories编写添加:

    org.springframework.context.ApplicationContextInitializer=com.mooc.sb2.initializer.FirstInitializer

    实现方式2

    • 实现ApplicationContextInitializer接口
    • 在springApplication类初始后设置进去
    1. @Order(2)
    2. public class SecondInitializer implements ApplicationContextInitializer {
    3. @Override
    4. public void initialize(ConfigurableApplicationContext applicationContext) {
    5. ConfigurableEnvironment environment = applicationContext.getEnvironment();
    6. Map map = new HashMap<>();
    7. map.put("key2", "value2");
    8. MapPropertySource mapPropertySource = new MapPropertySource("secondInitializer", map);
    9. environment.getPropertySources().addLast(mapPropertySource);
    10. System.out.println("run secondInitializer");
    11. }
    12. }

    设置:

    1. @SpringBootApplication
    2. @MapperScan("com.mooc.sb2.mapper")
    3. public class Sb2Application {
    4. public static void main(String[] args) {
    5. // SpringApplication.run(Sb2Application.class, args);
    6. SpringApplication springApplication = new SpringApplication(Sb2Application.class);
    7. springApplication.addInitializers(new SecondInitializer());
    8. springApplication.run(args);
    9. }
    10. }

    实现方式3

    • 实现ApplicationContextInitializer接口
    • application.properties内填写接口实现
      • key: context.initializer.classes
      • value值为自定义初始化器的全类名
    1. @Order(3)
    2. public class ThirdInitializer implements ApplicationContextInitializer {
    3. @Override
    4. public void initialize(ConfigurableApplicationContext applicationContext) {
    5. ConfigurableEnvironment environment = applicationContext.getEnvironment();
    6. Map map = new HashMap<>();
    7. map.put("key3", "value3");
    8. MapPropertySource mapPropertySource = new MapPropertySource("thirdInitializer", map);
    9. environment.getPropertySources().addLast(mapPropertySource);
    10. System.out.println("run thirdInitializer");
    11. }
    12. }
    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值失效的问题
  • 相关阅读:
    代码随想录算法训练营第三十三天丨 贪心算法part04
    Pytorch:复现PointNet
    Kafka内容相关
    java易错笔试题含答案一
    微信小程序连接蓝牙汉印HM-A300L标签打印机
    优思学院|韦伯的组织理论在今天还有意义吗?
    CUDA和OpenGL纹理texture结合
    传输层 拥塞控制-慢开始和拥塞避免 快重传 快恢复
    记一次前端CryptoJS AES解密
    PM项目管理职责
  • 原文地址:https://blog.csdn.net/Box_clf/article/details/134432461