SpringBoot 2.x版本启动流程
启动入口代码示例:
public static void main(String[] args) {
SpringApplication.run(xxx.class, args);
}
启动流程图
这里记录Springboot 2.x版本的启动流程,主要包含两个部分
第一个部分是创建SpringApplication对象,并对这个对象赋值操作,包括设置web应用类型、获取设置初始化器、获取设置监听器和设置mian方法所在主类;
第二个部分是执行run方法,包括获取监听器并发布各种事件、创建web容器上下文、准备上下文(执行初始化器)、刷新上下文(自动配置,创建Servlet容器并启动)、执行自定义run方法(ApplicationRunner、CommandLineRunner)等
接下来,逐个介绍各个步骤具体干了啥
创建SpringApplication对象
在mian方法中一般都是调用SpringApplication的静态run方法,并传入一个配置类和启动参数,这里其实是先new了一个SpringApplication对象实例,然后在调用run方法
2. 确定web应用类型
类型有3种:SERVLET
、REACTIVE
(响应式)和NONE
,根据应用中是否加载了相应的类,来确定web应用类型,如果项目引入了SERVLET
的依赖,那么web应用类型就是SERVLET
3.获取并设置初始化器
从项目或者所有依赖jar包的META-INFO/spring.factories
文件中查找以org.springframework.context.ApplicationContextInitializer
为key的所有ApplicationContextInitializer
实现类的全限定类名,并实例化这些对象,并设置给SpringApplication
对象的initializers
属性;这些ApplicationContextInitializer
将会在后面用到,这里也是扩展点之一,这些初始化器会在步骤13被执行
META-INFO/spring.factories
文件中里面定义很多的相关类,当中就包含大家熟知的各种自动配置类,格式是以key=value形式展现,value以”,“分割,效果如下
Debug源码找到如下这些ApplicationContextInitializer
实现类,共找到8个
它们分别是从spring-boot-devtools.jar
,spring-boot.jar
和spring-boot-autoconfigue.jar
中的META-INFO/spring.factories
文件中获取得到的,刚好对应上面找到的8个
了解到这里我们也可以自己写一个类,实现ApplicationContextInitializer
接口,放在项目的META-INFO/spring.factories
文件中,也是可以被读取到的
4.获取并设置监听器
获取方式跟上面步骤3一样,只不过这里获取org.springframework.context.ApplicationListener
5.确定main方法所在主类
借助于方法栈信息,确定main方法所在的类
执行run方法
执行run方法,传递args参数,即启动参数
7.创建计时器,记录启动时间
创建StopWatch对象,调用start方法记录SpringBoot启动时间
8.设置headless属性值
这里主要是设置系统属性java.awt.headless=true
,目的是告诉系统,应用可以在无任何输入、输出设备,照样运行,一般作为服务器端是可以不需要显示器,键盘等输入、输出设备的
9.获取应用启动监听器并发布开始启动事件
获取方式跟步骤3一样,从META-INFO/spring.factories
文件中获取org.springframework.boot.SpringApplicationRunListener
实现类,里面定义了一些方法,在应用启动过程中,用于发布对应启动过程的事件,如starting(应用启动事件)
、environmentPrepared(环境准备完毕事件)
等;这里也可以做为一个扩展点,去实现org.springframework.boot.SpringApplicationRunListener
接口对应的方法(注意:这里实现类需要有一个构造器,里面接收SpringApplication application, String[] args
这2个参数),即监听到对应事件里做自己的业务逻辑;
这里获取到了
springboot
的默认实现类EventPublishingRunListener
,它实现了此接口,里面主要是应用到一个类SimpleApplicationEventMulticaster(事件多播器)
,通过它来发布事件;
自定义一个监听器
10.准备环境,获取设置系统配置、应用配置
根据步骤1确定的web应用类型创建不同的环境对象Environment
,并获取系统环境配置,应用配置等信息,设置到环境对象中,以便后续使用
11.打印banner图
首先判断banner的打印模式(步骤1确定了为CONSOLE
模式,即控制台打印)如果为OFF则不打印,接下来,会查看resources文件下是否有banner.txt
或者banner.jpg(.png .gif)
,有的话,按照对应的打印模式打印相关的内容;如果没有,则执行默认的banner(SpringBootBanner
)里面定义了字符串,字符串的内容就是我们熟知的默认banner效果
自定义banner效果图,在resources文件下放入banner.txt
12.创建web应用上下文
根据步骤1指定的web应用类型创建对应的web应用上下文
13.准备web应用上下文
主要是为web应用上下文设置一些属性值,包括环境environment
、应用初始化器(步骤1获取的初始化器,就是在这里调用的)、发布环境准备事件、注册参数和banner成组件到BeanFactory
、加载BeanBefinition
(重要)、发布上下文加载完成事件等一系列内容
初始化器
ApplicationContextInitializer
,它里面有一个initialize
方法,参数是context
即上下文信息,拿到这个上下文那么不就可以想怎么改就怎么改了,前提是真正了解context
,所以也是扩展点之一
14.刷新web应用上下文
这里就涉及到Spring的相关内容,总之会调用到AbstractApplicationContext
的refresh
方法,不过调用的发起者是步骤12创建的web应用上下文(如,AnnotationConfigServletWebServerApplicationContext
),里面会重写refresh方法中的很多模板方法(留给子类重写的方法),如prepareRefresh
、postProcessBeanFactory
、onRefresh
等;其中重写的onRefresh
方法里面创建并启动了Servlet容器()(即,如内嵌Tomcat(了解SpringBoot内置Servlet容器原理));自动配置功能也是在这一步骤完成(了解SpringBoot自动配置)
重写的onRefresh
方法
15.执行自定义run方法
这里执行实现了ApplicationRunner
和CommandLineRunner
接口的run
方法,也算是一个扩展点吧
总结
总之SpringBoot是基于Spring框架的,通过以上的分析知道每个步骤大致做了什么,以及有哪些扩展点,知道自动配置,以及内嵌Serlvet在哪一步执行……以上是对SpringBoot启动流程的大致说明,忽略了一些细节,并没有深入去分析,有错误之处,希望给予指导!!!