1 如何编写一个SpringBoot启动类
我们都知道,我们运行一个SpringBoot项目,引入相关Starters
和相关依赖后,再编写一个启动类,然后在这个启动类标上@SpringBootApplication
注解,然后就可以启动运行项目了,如下代码:
1 | //MainApplication.java |
如上代码,我们在MainApplication
启动类上标注了@SpringBootApplication
注解,然后在main
函数中调用SpringApplication.run(MainApplication.class, args);
这句代码就完成了SpringBoot的启动流程,非常简单。
2 @SpringBootApplication
现在我们来分析下标注在启动类上的@SpringBootApplication
注解,直接上源码:
1 | // SpringBootApplication.java |
可以看到,@SpringBootApplication
注解是一个组合注解,主要由@SpringBootConfiguration
,@EnableAutoConfiguration
和@ComponentScan
这三个注解组合而成。
因此@SpringBootApplication
注解主要作为一个配置类,能够触发包扫描和自动配置的逻辑,从而使得SpringBoot的相关bean
被注册进Spring容器。
3 SpringBoot的启动流程是怎样的?
接下来是本篇的重点,我们来分析下SpringBoot的启动流程是怎样的?
我们接着来看前面main
函数里的SpringApplication.run(MainApplication.class, args);
这句代码,那么SpringApplication
这个类是干嘛的呢?
SpringApplication
类是用来启动SpringBoot项目的,可以在java的main
方法中启动,目前我们知道这些就足够了。下面看下SpringApplication.run(MainApplication.class, args);
这句代码的源码:
1 | // SpringApplication.java |
在上面的静态run
方法里又继续调用另一个静态run
方法:
1 | // SpringApplication.java |
如上代码,可以看到构建了一个SpringApplication
对象,然后再调用其run
方法来启动SpringBoot项目。关于SpringApplication
对象是如何构建的,我们后面再分析,现在直接来看下启动流程的源码:
1 | // SpringApplication.java |
如上代码就是SpringBoot的启动流程了,其中注释也非常详细,主要步骤也已经标注【x】
,现将主要步骤总结如下:
- 从
spring.factories
配置文件中加载EventPublishingRunListener
对象,该对象拥有SimpleApplicationEventMulticaster
属性,即在SpringBoot启动过程的不同阶段用来发射内置的生命周期事件; - 准备环境变量,包括系统变量,环境变量,命令行参数,默认变量,
servlet
相关配置变量,随机值以及配置文件(比如application.properties
)等; - 控制台打印SpringBoot的
bannner
标志; - 根据不同类型环境创建不同类型的
applicationcontext
容器,因为这里是servlet
环境,所以创建的是AnnotationConfigServletWebServerApplicationContext
容器对象; - 从
spring.factories
配置文件中加载FailureAnalyzers
对象,用来报告SpringBoot启动过程中的异常; - 为刚创建的容器对象做一些初始化工作,准备一些容器属性值等,对
ApplicationContext
应用一些相关的后置处理和调用各个ApplicationContextInitializer
的初始化方法来执行一些初始化逻辑等; - 刷新容器,这一步至关重要。比如调用
bean factory
的后置处理器,注册BeanPostProcessor
后置处理器,初始化事件广播器且广播事件,初始化剩下的单例bean
和SpringBoot创建内嵌的Tomcat
服务器等等重要且复杂的逻辑都在这里实现,主要步骤可见代码的注释,关于这里的逻辑会在以后的spring源码分析专题详细分析; - 执行刷新容器后的后置处理逻辑,注意这里为空方法;
- 调用
ApplicationRunner
和CommandLineRunner
的run方法,我们实现这两个接口可以在spring容器启动后需要的一些东西比如加载一些业务数据等; - 报告启动异常,即若启动过程中抛出异常,此时用
FailureAnalyzers
来报告异常; - 最终返回容器对象,这里调用方法没有声明对象来接收。
当然在SpringBoot启动过程中,每个不同的启动阶段会分别发射不同的内置生命周期事件,比如在准备environment
前会发射ApplicationStartingEvent
事件,在environment
准备好后会发射ApplicationEnvironmentPreparedEvent
事件,在刷新容器前会发射ApplicationPreparedEvent
事件等,总之SpringBoot总共内置了7个生命周期事件,除了标志SpringBoot的不同启动阶段外,同时一些监听器也会监听相应的生命周期事件从而执行一些启动初始化逻辑。
4 小结
好了,SpringBoot的启动流程就已经分析完了,这篇内容主要让我们对SpringBoot的启动流程有一个整体的认识,现在还没必要去深究每一个细节,以免丢了主线,现在我们对SpringBoot的启动流程有一个整体的认识即可,关于启动流程的一些重要步骤我们会在以后的源码分析中来深究。