Spring Boot的启动流程

转载:SpringBoot的启动流程是怎样的?SpringBoot源码(七)

注:该源码分析对应SpringBoot版本为2.1.0.RELEASE

1. 温故而知新

本篇接 SpringBoot内置的各种Starter是怎样构建的? SpringBoot源码(六)

温故而知新,我们来简单回顾一下上篇的内容,上一篇我们分析了SpringBootSpringBoot内置的各种Starter是怎样构建的?,现将关键点重新回顾总结下:

  1. spring-boot-starter-xxx起步依赖没有一行代码,而是直接或间接依赖了xxx-autoconfigure模块,而xxx-autoconfigure模块承担了spring-boot-starter-xxx起步依赖自动配置的实现;

  2. xxx-autoconfigure自动配置模块引入了一些可选依赖,这些可选依赖不会被传递到spring-boot-starter-xxx起步依赖中,这是起步依赖构建的关键点

  3. spring-boot-starter-xxx起步依赖显式引入了一些对自动配置起作用的可选依赖,因此会触发 xxx-autoconfigure自动配置的逻辑(比如创建某些符合条件的配置bean);

  4. 经过前面3步的准备,我们项目只要引入了某个起步依赖后,就可以开箱即用了,而不用手动去创建一些bean等。

2. 引言

本来这篇文章会继续SpringBoot自动配置的源码分析的,想分析下spring-boot-starter-web的自动配置的源码是怎样的的。但是考虑到spring-boot-starter-web的自动配置逻辑跟内置Tomcat等有关,因此想以后等分析了SpringBoot的内置Tomcat的相关源码后再来继续分析spring-boot-starter-web的自动配置的源码。

因此,本篇我们来探究下SpringBoot的启动流程是怎样的?

3. 如何编写一个Spring Boot启动类

我们都知道,我们运行一个SpringBoot项目,引入相关Starters和相关依赖后,再编写一个启动类,然后在这个启动类标上@SpringBootApplication注解,然后就可以启动运行项目了,如下代码:

如上代码,我们在MainApplication启动类上标注了@SpringBootApplication注解,然后在main函数中调用SpringApplication.run(MainApplication.class, args);这句代码就完成了SpringBoot的启动流程,非常简单。

4. @SpringBootApplication

现在我们来分析下标注在启动类上的@SpringBootApplication注解,直接上源码:

可以看到,@SpringBootApplication注解是一个组合注解,主要由@SpringBootConfiguration,@EnableAutoConfiguration@ComponentScan这三个注解组合而成。

因此@SpringBootApplication注解主要作为一个配置类,能够触发包扫描和自动配置的逻辑,从而使得SpringBoot的相关bean被注册进Spring容器。

5. SpringBoot的启动流程是怎样的?

接下来是本篇的重点,我们来分析下SpringBoot的启动流程是怎样的?

我们接着来看前面main函数里的SpringApplication.run(MainApplication.class, args);这句代码,那么SpringApplication这个类是干嘛的呢?

SpringApplication类是用来启动SpringBoot项目的,可以在java的main方法中启动,目前我们知道这些就足够了。下面看下SpringApplication.run(MainApplication.class, args);这句代码的源码:

在上面的静态run方法里又继续调用另一个静态run方法:

如上代码,可以看到构建了一个SpringApplication对象,然后再调用其run方法来启动SpringBoot项目。关于SpringApplication对象是如何构建的,我们后面再分析,现在直接来看下启动流程的源码:

如上代码就是SpringBoot的启动流程了,其中注释也非常详细,主要步骤也已经标注【x】,现将主要步骤总结如下:

  1. spring.factories配置文件中加载EventPublishingRunListener对象,该对象拥有SimpleApplicationEventMulticaster属性,即在SpringBoot启动过程的不同阶段用来发射内置的生命周期事件;

  2. 准备环境变量,包括系统变量,环境变量,命令行参数,默认变量,servlet相关配置变量,随机值以及配置文件(比如application.properties)等;

  3. 控制台打印SpringBoot的bannner标志

  4. 根据不同类型环境创建不同类型的applicationContext容器,因为这里是servlet环境,所以创建的是AnnotationConfigServletWebServerApplicationContext容器对象;

  5. spring.factories配置文件中加载FailureAnalyzers对象,用来报告SpringBoot启动过程中的异常;

  6. 为刚创建的容器对象做一些初始化工作,准备一些容器属性值等,对ApplicationContext应用一些相关的后置处理和调用各个ApplicationContextInitializer的初始化方法来执行一些初始化逻辑等;

  7. 刷新容器,这一步至关重要。比如调用bean factory的后置处理器,注册BeanPostProcessor后置处理器,初始化事件广播器且广播事件,初始化剩下的单例bean和SpringBoot创建内嵌的Tomcat服务器等等重要且复杂的逻辑都在这里实现,主要步骤可见代码的注释,关于这里的逻辑会在以后的spring源码分析专题详细分析;

  8. 执行刷新容器后的后置处理逻辑,注意这里为空方法;

  9. 调用ApplicationRunnerCommandLineRunner的run方法,我们实现这两个接口可以在spring容器启动后需要的一些东西比如加载一些业务数据等;

  10. 报告启动异常,即若启动过程中抛出异常,此时用FailureAnalyzers来报告异常;

  11. 最终返回容器对象,这里调用方法没有声明对象来接收。

当然在SpringBoot启动过程中,每个不同的启动阶段会分别发射不同的内置生命周期事件,比如在准备environment前会发射ApplicationStartingEvent事件,在environment准备好后会发射ApplicationEnvironmentPreparedEvent事件,在刷新容器前会发射ApplicationPreparedEvent事件等,总之SpringBoot总共内置了7个生命周期事件,除了标志SpringBoot的不同启动阶段外,同时一些监听器也会监听相应的生命周期事件从而执行一些启动初始化逻辑。

6. 小结

好了,SpringBoot的启动流程就已经分析完了,这篇内容主要让我们对SpringBoot的启动流程有一个整体的认识,现在还没必要去深究每一个细节,以免丢了主线,现在我们对SpringBoot的启动流程有一个整体的认识即可,关于启动流程的一些重要步骤我们会在以后的源码分析中来深究。

原创不易,帮忙点个赞呗!

由于笔者水平有限,若文中有错误还请指出,谢谢。

最后更新于

这有帮助吗?