本文共 9406 字,大约阅读时间需要 31 分钟。
springboot应用创建初始化流程和启动过程
文章目录
创建SpringBoot应用创建初始化流程分析
分析
我们现在启动类上的xxx.run()语句
上打断点,并使用DEBUG,如下
Step Into
进入org.springframework.boot.SpringApplication#run(java.lang.Class<?>, java.lang.String...)方法
再Step Into
进入org.springframework.boot.SpringApplication#run(java.lang.Class<?>[], java.lang.String[])方法
再Step Into
进入org.springframework.boot.SpringApplication#SpringApplication(java.lang.Class<?>...)方法
再Step Into
进入org.springframework.boot.SpringApplication#SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class<?>...)构造器
this.resourceLoader = resourceLoader;
:资源加载器Assert.notNull(primarySources, "PrimarySources must not be null");
:断言是否有主配置类;this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
:将断言获得的主配置类信息保存this.webApplicationType = WebApplicationType.deduceFromClasspath();
:判断当前WEB应用的类型;setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
:找初始化器ApplicationContextInitializer
,因为通过getSpringFactoriesInstances()方法
,所以会去spring.factories文件
中去找该类型的组件和其相关的值setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
:找应用监听器ApplicationListener
,因为通过getSpringFactoriesInstances()方法
,所以会去spring.factories文件
中去找该类型的组件和其相关的值this.mainApplicationClass = deduceMainApplicationClass();
:决定那个是我们的主程序
再一直Step Over
到如下位置
Step Into
进入org.springframework.boot.WebApplicationType#deduceFromClasspath方法
再Step Over
到如下位置 因此可以看出当前应用的类型是Servlet 再Step Over
到如下位置
this.initializers
下就有7个Initializer,如下: 再Step Over
到如下位置 此时我们会发现this.listeners
下就有11个listener,如下: 结论
springboot应用创建初始化流程(从上到下)
- 通过
ClassUtils
判断当前应用的类型,一般是判断出的是Servlet
; 初始启动引导器bootstrappers
,去spring.factories文件
中去找org.springframework.boot.Bootstrapper
类型的组件;- 找
初始化器ApplicationContextInitializer
,会去spring.factories文件
中去找该类型的组件和其相关的值; - 找
应用监听器ApplicationListener
,会去spring.factories文件
中去找该类型的组件和其相关的值 - 在SpringBoot中,只要看到了
getSpringFactoriesInstances(xxx)方法
,就表示去spring.factories文件
中去找xxx
类型的组件
SpringBoot应用启动过程分析
分析
首先在如下图位置设置断点,并以DEBUG运行
然后一直Step Into
至如下位置 再Step Into
至org.springframework.boot.SpringApplication方法
然后Step Out
该方法 再Step Into
进入==org.springframework.boot.SpringApplication#run(java.lang.String...)方法
== StopWatch stopWatch = new StopWatch();
停止观察器
StopWatch 的启动
Step Over
至如下位置
Step Into
进入org.springframework.util.StopWatch#start()方法
再次Step Into
进入org.springframework.util.StopWatch#start(java.lang.String)方法
,并一直Step Over
至如下位置 可以看到StopWatch
在调用start()方法
后会保存任务的名称
、项目启动的时间(纳秒计)
进入HEADLESS模式
再Step Over
至如下位置
Step Into
进入org.springframework.boot.SpringApplication#configureHeadlessProperty方法
SYSTEM_PROPERTY_JAVA_AWT_HEADLESS
是什么?我们跳转到该变量,发现:private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";
java.awt.headless
是什么?表示让当前应用进入HEADLESS模式,即“自力更生”模式;
获取所有的运行监听器SpringApplicationRunListeners
再Step Over
到如下位置
Step Into
进入org.springframework.boot.SpringApplication#getRunListeners方法
然后一直Step Over
到如下位置 getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)
表示从spring.factories文件
中找SpringApplicationRunListener
类型的组件; starting所有的运行监听器SpringApplicationRunListeners
我们Step Over
至如下位置
Step Into
进入org.springframework.boot.SpringApplicationRunListeners#starting方法
可以发现该方法是遍历所有的SpringApplicationRunListeners
类型的组件,并调用它们的starting()方法
(starting()方法
表示告知系统正在启动) 保存命令行参数
Step Over
至如下位置
args
,即命令行参数,相当于保存所有的命令行参数 准备基础环境
再Step Over
至如下位置
Step Into
进入org.springframework.boot.SpringApplication#prepareEnvironment方法
返回或创建基础环境信息
我们Step Into
进入org.springframework.boot.SpringApplication#getOrCreateEnvironment方法
配置环境
一直Step Over
至如下位置
Step Into
进入org.springframework.boot.ApplicationArguments#getSourceArgs方法
表示配置参数 再Step Over
到如下位置
Step Into
进入org.springframework.boot.SpringApplication#configureEnvironment方法
添加ConversionService
(类型转换器) configurePropertySources(environment, args);
:加载外部配置源
configureProfiles(environment, args);
:激活Profile
将配置好的环境信息绑定(保存)
Step Over
至如下位置
所有的SpringApplicationRunListeners执行environmentPrepared方法
Step Over
至如下位置
Step Into
进入org.springframework.boot.SpringApplicationRunListeners#environmentPrepared方法
可以看到遍历所有的SpringApplicationRunListener
类型的组件,并执行environmentPrepared方法
,表示通知所有的监听器当前环境准备完成; 绑定环境至SpringApplication
Step Into
至如下位置
配置需要忽略的Bean信息
Step Over
至如下位置
打印Banner
Step Over
至如下位置
创建IOC
Step Over
至如下位置
Step Into
进入org.springframework.boot.SpringApplication#createApplicationContext方法
可以看到会根据当前应用的类型创建指定的IOC 准备IOC的基本信息
Step Over
至如下位置
Step Into
进入org.springframework.boot.SpringApplication#prepareContext方法
context.setEnvironment(environment);
:将基础环境信息保存到IOC中postProcessApplicationContext(context);
:保存IOC容器的后置处理(包括注册组件<beanNameGenerator
>、读取配置文件的资源的资源加载器<resourceLoader
>、准备类型转换器<addConversionService
>)applyInitializers(context);
:应用初始化器listeners.contextPrepared(context);
:
保存IOC的后置处理流程
Step Into
进入org.springframework.boot.SpringApplication#postProcessApplicationContext方法
beanNameGenerator
>、读取配置文件的资源的资源加载器<resourceLoader
>、准备类型转换器<addConversionService
> 应用初始化器
Step Over
到如下位置
Step Into
进入org.springframework.boot.SpringApplication#applyInitializers方法
getInitializers()
:SpringBoot启动时再spring.factories文件
中的ApplicationContextInitializer
类型的组件 可以看到是遍历所有的ApplicationContextInitializer
类型的组件并调用它们的initialize()方法
,来对IOC容器进行初始化的扩展
所有运行监听器SpringApplicationRunListeners
调用其contextPrepared()方法
Step Over
至如下位置
Step Into
进入org.springframework.boot.SpringApplicationRunListeners#contextPrepared方法
可以看到调用了所有运行监听器SpringApplicationRunListeners
调用其contextPrepared()方法
获取Bean工厂,并注册一些单实例的组件
Step Over
至如下位置
所有运行监听器SpringApplicationRunListeners
调用其contextLoaded()方法
Step Over
至如下位置
Step Into
进入org.springframework.boot.SpringApplicationRunListeners#contextLoaded方法
可以看到调用了所有运行监听器SpringApplicationRunListeners
调用其contextLoaded()方法
刷新IOC容器
Step Over
至如下位置
Step Into
进入org.springframework.boot.SpringApplication#refreshContext方法
再Step Over
至如下位置 Step Into
进入org.springframework.boot.SpringApplication#refresh(org.springframework.context.ApplicationContext)方法
,并Step Over
至如下位置 然后再一直Step Into
至如下位置 可看到此时就是Spring容器经典的初始化容器过程,创建容器中的所有组件 IOC容器刷新完成后
Step Out
至如下位置
停止停止观察器StopWatch
Step Over
至如下位置
Step Into
进入org.springframework.util.StopWatch#stop方法
可以看到该方法包括了计算项目任务信息
、启动时间(纳秒计)
等的操作 所有运行监听器SpringApplicationRunListeners
调用其started()方法
Step Over
至如下位置
Step Into
进入org.springframework.boot.SpringApplicationRunListeners#started方法
可以看到所有的运行监听器SpringApplicationRunListeners
调用其started()方法
调用所有的Runners
Step Over
至如下位置
Step Into
进入org.springframework.boot.SpringApplication#callRunners方法
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
:获取容器中的ApplicationRunner
类型的组件runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
:获取容器中的CommandLineRunner
类型的组件AnnotationAwareOrderComparator.sort(runners);
:合并上面两种获取的组件,并按照@Order
注解排序for (Object runner : new LinkedHashSet<>(runners)) {...}
:遍历所有,然后通过ApplicationRunner
类型和CommandLineRunner
类型的不同调用对应的run()方法
如果上述存在异常,所有运行监听器SpringApplicationRunListeners
调用其failed()方法
如果上述都没有异常,所有运行监听器SpringApplicationRunListeners
调用其running()方法
Step Over
至如下位置
Step Into
进入org.springframework.boot.SpringApplicationRunListeners#running方法
可以看到所有运行监听器SpringApplicationRunListeners
调用其running()方法
部分源码
SpringApplicationRunListener的结构图如下:
ApplicationRunner接口
package org.springframework.boot;import org.springframework.core.Ordered;import org.springframework.core.annotation.Order;@FunctionalInterfacepublic interface ApplicationRunner { /** * Callback used to run the bean. * @param args incoming application arguments * @throws Exception on error */ void run(ApplicationArguments args) throws Exception;}
CommandLineRunner接口
package org.springframework.boot;import org.springframework.core.Ordered;import org.springframework.core.annotation.Order;@FunctionalInterfacepublic interface CommandLineRunner { /** * Callback used to run the bean. * @param args incoming main method arguments * @throws Exception on error */ void run(String... args) throws Exception;}
结论
springboot应用启动过程(从上至下)
- 会创建并启动
停止观察器StopWatch
,该观察器会保存任务的名称
、项目启动的时间(纳秒计)
; - 让当前应用进入HEADLESS模式(
java.awt.headless
,自力更生模式); - 获取所有的
运行监听器SpringApplicationRunListeners
; - 遍历所有的
运行监听器SpringApplicationRunListeners
,并依次调用它们的starting()方法
,表示告知系统正在启动,为了方便所有的Listener进行事件感知; - 保存命令行参数
- 准备基础环境
- 返回或创建基础环境信息
- 配置环境信息
- 读取所有的配置源的配置属性值
- 绑定(保存)配置好的环境信息
- 遍历所有的
运行监听器SpringApplicationRunListeners
类型的组件,并依次调用它们的environmentPrepared方法
,通知当前环境准备完成; - 绑定环境至SpringApplication
- …
- 配置需要忽略的Bean信息
- 根据当前项目的类型创建IOC
- 准备IOC容器的基本信息
- 将基础环境信息保存到IOC
- IOC容器后置处理
应用初始化器applylnitializers
- 遍历所有的
ApplicationContextInitializer
类型的组件并调用它们的initialize()方法
,来对IOC容器进行初始化的扩展
- 遍历所有的
- 所有
运行监听器SpringApplicationRunListeners
调用其contextPrepared()方法
- 进行一系列的其他操作
- 所有
运行监听器SpringApplicationRunListeners
调用其contextLoaded()方法
- 刷新IOC容器
- 实例化容器中的所有组件(通过Spring)
- IOC刷新完成后的操作
- 停止
停止观察器StopWatch
- 所有
运行监听器SpringApplicationRunListeners
调用其started()方法
- 调用所有的
Runners
- 获取容器中的
ApplicationRunner
类型的组件和CommandLineRunner
类型的组件 - 合并上面两种获取的组件,并按照
@Order
注解排序 - 遍历所有,然后通过
ApplicationRunner
类型和CommandLineRunner
类型的不同调用对应的run()方法
- 获取容器中的
- 如果以上有异常出现,会调用所有
运行监听器SpringApplicationRunListeners
的failed()方法
,表示告知系统进入失败状态;如果以上没有异常,会调用所有运行监听器SpringApplicationRunListeners
调用其running()方法
,表示告知系统进入运行状态; eners调用其
contextLoaded()方法` - 刷新IOC容器
- 实例化容器中的所有组件(通过Spring)
- IOC刷新完成后的操作
- 停止
停止观察器StopWatch
- 所有
运行监听器SpringApplicationRunListeners
调用其started()方法
- 调用所有的
Runners
- 获取容器中的
ApplicationRunner
类型的组件和CommandLineRunner
类型的组件 - 合并上面两种获取的组件,并按照
@Order
注解排序 - 遍历所有,然后通过
ApplicationRunner
类型和CommandLineRunner
类型的不同调用对应的run()方法
- 获取容器中的
- 如果以上有异常出现,会调用所有
运行监听器SpringApplicationRunListeners
的failed()方法
,表示告知系统进入失败状态;如果以上没有异常,会调用所有运行监听器SpringApplicationRunListeners
调用其running()方法
,表示告知系统进入运行状态; - 如果调用
running()方法
出现异常,同样也会调用failed()方法
通知系统进入失败状态;
转载地址:https://blog.csdn.net/m0_49039508/article/details/117068472 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!