本文共 946字,阅读大约需要 3分钟,文末有计时器可自行对时!


概   述

说到接触 SpringBoot 伊始,给我第一映像最深的是有两个关键元素:

对照上面的典型代码,这个两个元素分别是:

  • @SpringBootApplication

  • SpringApplication 以及 run() 方法

关于 @SpringBootApplication 注解的剖析已经在上文:《SpringBoot 中 @SpringBootApplication注解背后的三体结构探秘》中完成了,其实它背后就是一个三体结构,只是 SpringBoot给了其一个包装而已。那么本文我们就来看看这个 SpringApplication 以及 run() 方法 到底是个什么鬼,它背后又隐藏了哪些奥秘呢?

注: 本文首发于 My 公众号 CodeSheep ,可 长按  扫描 下面的 小心心 来订阅 ↓ ↓ ↓

本文内容脑图如下:


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()方法探秘

先看看代码长啥样子:

各个主要步骤我已经标注在上图之中了,除此之外,我也按照自己的理解画了一个流程图如下所示,可以对照数字标示看一下:

我们将各步骤总结精炼如下:

  1. 通过 SpringFactoriesLoader 加载 META-INF/spring.factories 文件,获取并创建 SpringApplicationRunListener 对象

  2. 然后由 SpringApplicationRunListener 来发出 starting 消息

  3. 创建参数,并配置当前 SpringBoot 应用将要使用的 Environment

  4. 完成之后,依然由 SpringApplicationRunListener 来发出 environmentPrepared 消息

  5. 创建 ApplicationContext

  6. 初始化 ApplicationContext,并设置 Environment,加载相关配置等

  7. 由 SpringApplicationRunListener 来发出 contextPrepared 消息,告知SpringBoot 应用使用的 ApplicationContext 已准备OK

  8. 将各种 beans 装载入 ApplicationContext,继续由 SpringApplicationRunListener 来发出 contextLoaded 消息,告知 SpringBoot 应用使用的 ApplicationContext 已装填OK

  9. refresh ApplicationContext,完成IoC容器可用的最后一步

  10. 由 SpringApplicationRunListener 来发出 started 消息

  11. 完成最终的程序的启动

  12. 由 SpringApplicationRunListener 来发出 running 消息,告知程序已运行起来了

至此,全流程结束!



后  记

由于能力有限,若有错误或者不当之处,还请大家批评指正,一起学习交流!

  • 我的个人博客:www.codesheep.cn


如果有兴趣,也可以抽时间看看作者关于容器化、微服务化方面的文章:

  • 我的半年技术博客之路

  • 利用K8S技术栈打造个人私有云连载文章

  • Spring Boot Admin 2.0 上手体验

  • 利用TICK搭建Docker容器可视化监控中心

  • 从一份配置清单详解Nginx服务器配置

  • Docker容器可视化监控中心搭建

  • 利用ELK搭建Docker容器化应用日志中心

  • 高效编写Dockerfile的几条准则

  • Docker容器跨主机通信

  • Spring Boot应用监控实战

  • RPC框架实践之:Google gRPC

  • RPC框架实践之:Apache Thrift

  • 微服务调用链追踪中心搭建



作者更多 务实、能看懂、可复现的 原创文章尽在公众号 CodeSheep,欢迎订阅 ⬇️⬇️⬇️


©著作权归作者所有:来自51CTO博客作者mb5fdcae83766b7的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. Docker容器跨主机通信之:直接路由方式
  2. 利用TICK搭建Docker容器可视化监控中心
  3. DoDAF2.0方法论探究
  4. SpringBoot应用部署于外置Tomcat容器
  5. http协议请求方法都有哪些?网络安全学习提升
  6. 【前端词典】8 个提高 JS 性能的方法
  7. AngularJS 日期时间选择组件(附详细使用方法)
  8. 5 种方法教你用Python玩转histogram直方图

随机推荐

  1. Error reading device /dev/bakupvg/baku
  2. 个人理解简单工厂模式和策略模式的区别
  3. 多线程学习(三)多线程开发带来的问题与解决
  4. 为什么说Python会成为最流行的编程语言?
  5. IPython6.0发布:放弃支持Python2.7
  6. Django2.0即将带来3个重要特性
  7. 多线程学习(三)那些队列可用于线程池
  8. 用翻译赚钱,翻译社规则调整
  9. Fedora写给Python的情书
  10. 值得关注的5个Python开源项目