SpringBoot 应用程序启动过程探秘
概述
说到接触 SpringBoot 伊始,给我第一映像最深的是有两个关键元素:
对照上面的典型代码,这个两个元素分别是:
- @SpringBootApplication
- SpringApplication 以及 run() 方法
关于 @SpringBootApplication 注解的剖析已经在上文:《SpringBoot 中 @SpringBootApplication注解背后的三体结构探秘》 中完成了,其实它背后就是一个三体结构,只是 SpringBoot给了其一个包装而已。那么本文我们就来看看这个 SpringApplication 以及 run() 方法 到底是个什么鬼,它背后又隐藏了哪些奥秘呢?
本文内容脑图如下:
SpringApplication 惊鸿一瞥
SpringApplication 这个类应该算是 SpringBoot 框架 的“创新”产物了,原始的 Spring中并没有这个类,SpringApplication 里面封装了一套 Spring 应用的启动流程,然而这对用户完全透明,因此我们上手 SpringBoot 时感觉简洁、轻量。
一般来说默认的 SpringApplication 执行流程已经可以满足大部分需求,但是 若用户想干预这个过程,则可以通过 SpringApplication 在流程某些地方开启的 扩展点 来完成对流程的扩展,典型的扩展方案那就是使用 set 方法。
我们来举一个栗子,把我们天天司空见惯的 SpringBoot 应用的启动类来拆解一下写出来:
@SpringBootApplication
public class CodeSheepApplication {
public static void main( String[] args ) {
// SpringApplication.run( CodeSheepApplication.class args ); // 这是传统SpringBoot应用的启动,一行代码搞定,内部默认做了很多事
SpringApplication app = new SpringApplication( CodeSheepApplication.class );
app.setXXX( ... ); // 用户自定的扩展在此 !!!
app.run( args );
}
}
复制代码
这样一拆解后我们发现,我们也需要先构造 SpringApplication 类对象,然后调用该对象的 run() 方法。那么接下来就讲讲 SpringApplication 的构造过程 以及其 run() 方法的流程,搞清楚了这个,那么也就搞清楚了SpringBoot应用是如何运行起来的!
SpringApplication 实例的初始化
我们对照代码来看:
四个关键的步骤已标注在图中,分别解释如下:
- ① 推断应用的类型:创建的是 REACTIVE应用、SERVLET应用、NONE 三种中的某一种
- ② 使用
SpringFactoriesLoader查找并加载 classpath下META-INF/spring.factories文件中所有可用的ApplicationContextInitializer
- ③ 使用
SpringFactoriesLoader查找并加载 classpath下META-INF/spring.factories文件中的所有可用的ApplicationListener
- ④ 推断并设置 main方法的定义类
SpringApplication 的run()方法探秘
先看看代码长啥样子:
各个主要步骤我已经标注在上图之中了,除此之外,我也按照自己的理解画了一个流程图如下所示,可以对照数字标示看一下:
我们将各步骤总结精炼如下:
通过
SpringFactoriesLoader加载META-INF/spring.factories文件,获取并创建SpringApplicationRunListener对象然后由
SpringApplicationRunListener来发出 starting 消息创建参数,并配置当前 SpringBoot 应用将要使用的 Environment
完成之后,依然由
SpringApplicationRunListener来发出 environmentPrepared 消息创建
ApplicationContext初始化
ApplicationContext,并设置 Environment,加载相关配置等由
SpringApplicationRunListener来发出contextPrepared消息,告知SpringBoot 应用使用的ApplicationContext已准备OK将各种 beans 装载入
ApplicationContext,继续由SpringApplicationRunListener来发出 contextLoaded 消息,告知 SpringBoot 应用使用的ApplicationContext已装填OKrefresh ApplicationContext,完成IoC容器可用的最后一步
由
SpringApplicationRunListener来发出 started 消息完成最终的程序的启动
由
SpringApplicationRunListener来发出 running 消息,告知程序已运行起来了
至此,全流程结束!
后记
SpringBoot 应用程序启动过程探秘的更多相关文章
- Envoy 源码分析--程序启动过程
目录 Envoy 源码分析--程序启动过程 初始化 main 入口 MainCommon 初始化 服务 InstanceImpl 初始化 启动 main 启动入口 服务启动流程 LDS 服务启动流程 ...
- 【玩转SpringBoot】通过事件机制参与SpringBoot应用的启动过程
生命周期和事件监听 一个应用的启动过程和关闭过程是归属到“生命周期”这个概念的范畴. 典型的设计是在启动和关闭过程中会触发一系列的“事件”,我们只要监听这些事件,就能参与到这个过程中来. 要想监听事件 ...
- 【玩转SpringBoot】SpringBoot应用的启动过程一览表
SpringBoot应用的启动方式很简单,就一行代码,如下图01: 其实这行代码背后主要执行两个方法,一个是构造方法,一个是run方法. 构造方法主要内容就是收集一些数据,和确认一些信息.如下图02: ...
- 深入理解UIApplication和ios程序启动过程
在深入理解UIApplication前我们先了解ios程序的启动过程: UIApplication类在ios里面为app的管理和协调提供一个集中的点,每一个app有一个UIApplication的实例 ...
- [转] - C++程序启动过程
先说编译.链接过程1.预编译展开宏2.为每一个.cxx源文件编译一个目标文件3.编译器合成这些目标文件成一个库文件,同时解析可以找到的符号引用4.连接器把目标的库文件和所需要的引用的静.动态链接库进行 ...
- [iOS基础控件 - 6.10.6] UIApplicationDelegate & 程序启动过程
A.概念 1.移动app非常容易受到其他的系统.软件事件的干扰,如来电.锁屏 2.app受到干扰的时候,UIApplication会通知delegate,来代理处理干扰事件 3.delegate可以处 ...
- Android应用程序启动过程源代码分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6689748 前文简要介绍了Android应用程 ...
- Android 应用程序启动过程源代码分析
本文转自:http://blog.csdn.net/luoshengyang/article/details/6689748 前文简要介绍了Android应用程序的Activity的启动过程.在And ...
- Android程序启动过程深入解析
当按下Android设备电源键时究竟发生了什么? Android的启动过程是怎么样的? 什么是Linux内核? 桌面系统linux内核与Android系统linux内核有什么区别? 什么是引导装载程序 ...
随机推荐
- 重读ORB_SLAM之LocalMapping线程难点
1. 认清几个锁与布尔参数 线程的通信与相互影响在ORB比较复杂,需要好好缕清思路. 1.1 mbStopRequested,由RequestStop函数设定,主要是在回环线程里,在运行全局优化时,以 ...
- vs 删除代码中空行
原文:vs 删除代码中空行 ^\s*\n 正则表达式
- L2Dwidget
只需要在[页首html代码]中引入L2Dwidget.js即可.<!-- 右下角live2d效果 --> <script src="https://eqcn.ajz.mie ...
- paint进阶(转)
转自:https://blog.csdn.net/cquwentao/article/details/51374994 概述 paint的基本绘制方法已经在前面的基本图形绘制中讲解了,这里做的是进阶讲 ...
- 力扣—Remove Nth Node From End of List(删除链表的倒数第N个节点) python实现
题目描述: 中文: 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点. 示例: 给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了倒数第二 ...
- java23种设计模式(二)-- 建造者模式和原型模式
一.建造者模式 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创造不同的表示. 特点: (1).在某些属性没有赋值之前,复杂对象不能作为一个完整的产品使用.比如汽车包括方向盘.车门.发动机 ...
- C++ 字符串截取转换及字符流控制
文章由来 ------------------工作需要缓冲区里的字符串控制,还是混合编译的那种,根据协议来定义截取各种字符流,控制大小长度,截取返回的内容然后转换成特定的类型, 可能表述不是那么正确, ...
- python字符串的截取,查找
1.字符串的截取 str = "123456" str[:3] = 123 str[1:3] = 23 str[0:-1] = 12345 里面的数字都是index索引,从第一个索 ...
- PHP发送公众号模板消息
<?php /* * 模板消息发送,电脑端测试时需要手动填写openid * 微信端会自动获取当前openid发送无需填写 */ header("Content-type: text/ ...
- 【多线程】LinkedTransferQueue
LinkedTransferQueue是JDK1.7才添加的阻塞队列,基于链表实现的FIFO无界阻塞队列,是ConcurrentLinkedQueue(循环CAS+volatile 实现的wait-f ...