Loading

SpringBoot启动流程学习

本文主要讲解SpringBoot的启动流程

环境:SpringBoot 2.4.2

首先,我们在主启动类加上断点,开启debug

step into,直到显示这一行

从这一行可以看出来,SpringBoot的启动流程大体上分为两步,第一步是创建SpringApplication,第二步是运行SpringApplication

1. 创建SpringApplication

我们进入创建SpringApplication的流程,首先进入SpringApplication的构造方法

在构造方法内部,

  1. 首先保存了一些信息

  2. 判定了当前应用的类型为Servlet(使用ClassUtils工具类判定)

  3. 设定bootstrappers初始引导启动器,保存在List<Bootstrapper> bootstrappers中:从classpath的spring.factories文件中去找org.springframework.boot.Bootstrapper(在此项目中,没有找到)

  4. spring.factories中找ApplicationContextInitializer.class应用初始化器,保存在List<ApplicationContextInitializer<?>> initializers中(找到了7个)

  5. spring.factories中找ApplicationListener.class应用监听器,保存在List<ApplicationListener<?>> listeners中(找到了9个)

  6. 调用deduceMainApplicationClass方法寻找主程序类,寻找方法是在堆栈中找到有main方法的第一个类,就是应用的主程序类(在此项目中就是DemoApplication)

总之,创建SpringApplication的过程就是将一些信息保存在SpringApplication类中

2. 运行SpringApplication

在创建完SpringApplication对象后,就进行SpringApplication的运行工作,我们进入run方法

2.1 准备工作

  1. 创建StopWatch用来监控应用的开始和停止

  2. 记录应用的启动时间

  3. 调用createBootstrapContext方法创建引导上下文:对之前保存的bootstrappers挨个遍历执行intitialize方法来完成对引导启动器上下文环境的设置

  4. 让当前应用进入headless模式:java.awt.headless

  5. 获取所有RunListener运行监听器:从spring.factories中找SpringApplicationRunListener.class

  6. 遍历所有的RunListener,调用starting方法。相当于通知所有感兴趣系统正在启动的人,项目正在starting,这一部分涉及到自定义SpringBoot启动过程

2.2 创建并配置环境信息

  1. 保存命令行参数,保存到ApplicationArguments实例中

  2. 调用prepareEnvironment方法准备环境:

    调用getOrCreateEnvironment方法得到环境对象:如果环境信息已经存在,直接返回使用;如果环境信息没有,则创建环境信息对象,不同的应用创建不同的环境信息,SERVLET -> StandardServletEnvironmentREACTIVE -> StandardReactiveWebEnvironmentdefault -> StandardEnvironment

  3. 配置环境信息对象

    首先添加ConversionService,里面包括了很多的类型转换器,然后执行configurePropertySources(environment, args);加载外部配置源,读取所有配置源的属性值

  4. 绑定环境信息

  5. 所有监听器都挨个调用environmentPrepared方法:表示通知所有监听器当前环境已经准备完成

2.3 打印banner

在准备完环境信息之后,调用printBanner方法打印banner

在运行完这一行之后,在命令行界面可以看到banner信息

2.4 创建IOC容器

接下来就到了关键的部分,SpringBoot要创建IOC容器,也就是ApplicationContext

  1. 首先根据项目类型创建容器

  2. 调用prepareContext方法准备IOC容器ApplicationContext的基本信息
    首先保存之前设置的环境信息
    进行IOC容器的后置处理流程
    执行applyInitializers(context);应用之前获取的初始化器(第1章,步骤4):遍历所有的ApplicationContextInitializer,挨个调用对应的initialize方法,对IOC容器进行初始化扩展功能
    执行listeners.contextPrepared(context);,遍历之前获得的所有listener应用监听器(2.1,步骤5),只有1个,EventPublishingRunListener,调用对应的contextPrepared方法,通知所有监听器contextPrepared
    给容器中添加一些特殊的bean

    执行listeners.contextLoaded(context);,通知所有监听器contextLoaded

  1. 执行refreshContext(context);刷新IOC容器
    这一步骤会创建出容器中的所有组件,具体的过程参考Spring底层原理

  2. 执行afterRefresh(context, applicationArguments);,表示容器刷新后完成的工作

  3. 执行listeners.started(context);,通知所有监听器started

  4. 调用所有的Runner
    获取容器中的ApplicationRunner
    获取容器中的CommandLineRunner
    合并所有Runner并按照@Order进行排序
    遍历所有Runner,调用对应的run方法

  5. 如果以上步骤出现了异常,SpringBoot会执行listeners.failed(context, exception);,通知所有监听器应用failed

  1. 执行listeners.running(context);,调用监听器的running方法,通知所有监听器应用正在running
    如果running出现异常,则继续调用listeners.failed(context, exception);

至此,IOC容器创建完成

3. 总结

SpringBoot启动流程比较复杂,期间涉及到许多的监听器和事件监听机制,需要深入学习

posted @ 2021-02-14 23:14  Kinopio  阅读(356)  评论(0编辑  收藏  举报