你知道SpringBoot项目是怎么启动的吗

概述

SpringBoot是由Pivotal团队在2013年开始研发、2014年4月发布第一个版本的全新开源的轻量级框架。它基于Spring4.0设计,不仅继承了Spring框架原有的优秀特性,而且还通过简化配置来进一步简化了Spring应用的整个搭建和开发过程。另外SpringBoot通过集成大量的框架使得依赖包的版本冲突,以及引用的不稳定性等问题得到了很好的解决。

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

SpringApplication.run( ... );

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

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

SpringApplication

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

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

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

@SpringBootApplication
public class FrontNovelApplication {
    
    public static void main(String[] args) {
        // 这是传统Spring Boot应用的启动,一行代码搞定,内部默认做了很多事
        SpringApplication.run(FrontNovelApplication.class);

        // 用户自定的扩展在此 !!!
        SpringApplication app = new SpringApplication(FrontNovelApplication.class);
        //app.setXXX();这里能做很多自定义的事情。
        app.setBanner((environment, sourceClass, out) -> out.println(100));
        app.run(args);
    }

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

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

SpringApplication实例的初始化

还是先对照代码来看:
你知道SpringBoot项目是怎么启动的吗

图中红框标注的是四个关键的步骤,分别解释如下:

① 推断应用的类型:创建的是REACTIVE应用、SERVLET应用、NONE 三种中的某一种
你知道SpringBoot项目是怎么启动的吗

② 使用SpringFactoriesLoader查找并加载classpath下META-INF/spring.factories文件中所有可用的 ApplicationContextInitializer
你知道SpringBoot项目是怎么启动的吗

③ 使用SpringFactoriesLoader查找并加载classpath下META-INF/spring.factories文件中的所有可用的 ApplicationListener
你知道SpringBoot项目是怎么启动的吗

④ 推断并设置main方法的定义类
你知道SpringBoot项目是怎么启动的吗

SpringApplication的run()方法探秘

先看看代码长啥样子:
你知道SpringBoot项目是怎么启动的吗

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

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(…)方法,让实现了ApplicationRunner和CommandLineRunner接口类的run 方法得以执行,用于在 Spring 应用上下文准备完毕后,执行一些额外操作。从而完成最终的程序的启动。

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

至此,全流程结束。

上一篇:CAS


下一篇:springboot中 利用java反射调用Service,注入Dao接口为null