SpringBoot启动流程学习
本文主要讲解SpringBoot的启动流程
环境:SpringBoot 2.4.2
首先,我们在主启动类加上断点,开启debug
step into,直到显示这一行
从这一行可以看出来,SpringBoot的启动流程大体上分为两步,第一步是创建SpringApplication
,第二步是运行SpringApplication
1. 创建SpringApplication
我们进入创建SpringApplication的流程,首先进入SpringApplication的构造方法
在构造方法内部,
-
首先保存了一些信息
-
判定了当前应用的类型为Servlet(使用ClassUtils工具类判定)
-
设定
bootstrappers
初始引导启动器,保存在List<Bootstrapper> bootstrappers
中:从classpath的spring.factories
文件中去找org.springframework.boot.Bootstrapper
(在此项目中,没有找到) -
从
spring.factories
中找ApplicationContextInitializer.class
应用初始化器,保存在List<ApplicationContextInitializer<?>> initializers
中(找到了7个) -
从
spring.factories
中找ApplicationListener.class
应用监听器,保存在List<ApplicationListener<?>> listeners
中(找到了9个) -
调用
deduceMainApplicationClass
方法寻找主程序类,寻找方法是在堆栈中找到有main方法的第一个类,就是应用的主程序类(在此项目中就是DemoApplication)
总之,创建SpringApplication的过程就是将一些信息保存在SpringApplication类中
2. 运行SpringApplication
在创建完SpringApplication对象后,就进行SpringApplication的运行工作,我们进入run方法
2.1 准备工作
-
创建
StopWatch
用来监控应用的开始和停止 -
记录应用的启动时间
-
调用
createBootstrapContext
方法创建引导上下文:对之前保存的bootstrappers挨个遍历执行intitialize
方法来完成对引导启动器上下文环境的设置 -
让当前应用进入headless模式:
java.awt.headless
-
获取所有
RunListener
运行监听器:从spring.factories
中找SpringApplicationRunListener.class
-
遍历所有的
RunListener
,调用starting
方法。相当于通知所有感兴趣系统正在启动的人,项目正在starting,这一部分涉及到自定义SpringBoot启动过程
2.2 创建并配置环境信息
-
保存命令行参数,保存到
ApplicationArguments
实例中 -
调用
prepareEnvironment
方法准备环境:
调用getOrCreateEnvironment
方法得到环境对象:如果环境信息已经存在,直接返回使用;如果环境信息没有,则创建环境信息对象,不同的应用创建不同的环境信息,SERVLET
->StandardServletEnvironment
,REACTIVE
->StandardReactiveWebEnvironment
,default
->StandardEnvironment
-
配置环境信息对象
首先添加ConversionService
,里面包括了很多的类型转换器,然后执行configurePropertySources(environment, args);
加载外部配置源,读取所有配置源的属性值 -
绑定环境信息
-
所有监听器都挨个调用
environmentPrepared
方法:表示通知所有监听器当前环境已经准备完成
2.3 打印banner
在准备完环境信息之后,调用printBanner
方法打印banner
在运行完这一行之后,在命令行界面可以看到banner信息
2.4 创建IOC容器
接下来就到了关键的部分,SpringBoot要创建IOC容器
,也就是ApplicationContext
-
首先根据项目类型创建容器
-
调用
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
-
执行
refreshContext(context);
刷新IOC容器
这一步骤会创建出容器中的所有组件,具体的过程参考Spring底层原理 -
执行
afterRefresh(context, applicationArguments);
,表示容器刷新后完成的工作 -
执行
listeners.started(context);
,通知所有监听器started -
调用所有的
Runner
获取容器中的ApplicationRunner
获取容器中的CommandLineRunner
合并所有Runner并按照@Order
进行排序
遍历所有Runner,调用对应的run方法 -
如果以上步骤出现了异常,SpringBoot会执行
listeners.failed(context, exception);
,通知所有监听器应用failed
- 执行
listeners.running(context);
,调用监听器的running方法,通知所有监听器应用正在running
如果running出现异常,则继续调用listeners.failed(context, exception);
至此,IOC容器创建完成
3. 总结
SpringBoot启动流程比较复杂,期间涉及到许多的监听器和事件监听机制,需要深入学习