springboot应用创建初始化流程和启动过程
发布日期:2021-06-29 20:01:54 浏览次数:2 分类:技术文章

本文共 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 Intoorg.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方法

在这里插入图片描述
可以看到:保存IOC容器的后置处理包括注册组件<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()方法
  • 如果以上有异常出现,会调用所有运行监听器SpringApplicationRunListenersfailed()方法,表示告知系统进入失败状态;如果以上没有异常,会调用所有运行监听器SpringApplicationRunListeners调用其running()方法,表示告知系统进入运行状态;
    eners调用其contextLoaded()方法`
  • 刷新IOC容器
    • 实例化容器中的所有组件(通过Spring)
  • IOC刷新完成后的操作
  • 停止停止观察器StopWatch
  • 所有运行监听器SpringApplicationRunListeners调用其started()方法
  • 调用所有的Runners
    • 获取容器中的ApplicationRunner类型的组件和CommandLineRunner类型的组件
    • 合并上面两种获取的组件,并按照@Order注解排序
    • 遍历所有,然后通过ApplicationRunner类型和CommandLineRunner类型的不同调用对应的run()方法
  • 如果以上有异常出现,会调用所有运行监听器SpringApplicationRunListenersfailed()方法,表示告知系统进入失败状态;如果以上没有异常,会调用所有运行监听器SpringApplicationRunListeners调用其running()方法,表示告知系统进入运行状态;
  • 如果调用running()方法出现异常,同样也会调用failed()方法通知系统进入失败状态;

转载地址:https://blog.csdn.net/m0_49039508/article/details/117068472 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Java——使用数组和单链表模拟栈
下一篇:IDEA基本使用以及常用的配置和快捷键(会持续完善)

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2024年05月03日 14时55分05秒