你知道Spring Boot项目是怎么启动的吗?

2022-07-18 12:55:37


概 述

Java后端开发领域,大名鼎鼎的Spring Boot框架想必大家都用过。

用过Spring Boot的应该都知道,在项目启动入口的主类main()方法里,一句简简单单的

SpringApplication.run( ... );

便开启了项目的启动运行之路。

那么本文我们就来看看这个SpringApplication 以及run() 方法 到底是个什么鬼,它背后又隐藏了哪些奥秘呢?


SpringApplication一瞥

SpringApplication 这个类应该算是 Spring Boot 框架 本身的“创新”产物了,因为原始的Spring框架中并没有这个类,SpringApplication 里面封装了一套Spring应用的启动流程,然而这对用户完全透明,因此我们上手 Spring Boot 时感觉简洁且轻量。

一般来说默认的SpringApplication 执行流程已经可以满足大部分需求,但是 若用户想干预这个过程,则可以通过SpringApplication 在流程某些地方开启的扩展点 来完成对流程的扩展,典型的扩展方案那就是使用set 方法。

我们来举一个栗子,把我们天天司空见惯的 Spring Boot 应用的启动类来拆解一下写出来:

@SpringBootApplication
public class CodeSheepApplication {
 public static void main( String[] args ) {
  // SpringApplication.run( CodeSheepApplication.class args ); // 这是传统Spring Boot应用的启动,一行代码搞定,内部默认做了很多事
  SpringApplication app = new SpringApplication( CodeSheepApplication.class );
  app.setXXX( ... ); // 用户自定的扩展在此 !!!
  app.run( args );
 }
}

这样一拆解后我们发现,我们也需要先构造SpringApplication 类对象,然后调用该对象的run() 方法。

那么接下来就聊聊SpringApplication 的构造过程 以及其run()方法的流程,搞清楚了这个,那么也就搞清楚了Spring Boot应用是如何运行起来的了。


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 消息,告知Spring Boot 应用使用的ApplicationContext 已准备OK

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

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

  10. SpringApplicationRunListener 来发出started 消息

  11. 调用callRunners(...)方法,让实现了ApplicationRunnerCommandLineRunner接口类的run 方法得以执行,用于在 Spring 应用上下文准备完毕后,执行一些额外操作。从而完成最终的程序的启动。

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

至此,全流程结束。

推荐阅读
你亲手写的代码,正在出卖你

深夜,聊聊架构设计

深夜,分享一个Git小技巧

编程·思维·职场
欢迎扫码关注
  • 作者:singwhatiwanna
  • 原文链接:https://blog.csdn.net/singwhatiwanna/article/details/109610319
    更新时间:2022-07-18 12:55:37