springboot启动原理分析

在 Spring Boot 项目的启动类中常见代码如下:

springboot启动原理分析

springboot启动原理分析

一、SpringApplication 初始化

探究SpringApplication.run() 的实现

在这个静态方法中,创建 SpringApplication 对象,并调用该对象的 run 方法。

首先是进入单个参数的构造方法,然后进入两参数的构造方法(ResourceLoader 为 null),然后进行初始化。

springboot启动原理分析

1、deduceWebApplicationType() : 推断应用的类型

判断创建的是一个 SERVLET 应用还是 REACTIVE应用或者是 NONE

springboot启动原理分析

2、初始化 classpath 下的所有的可用的 ApplicationContextInitializer

setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))

1)、getSpringFactoriesInstances()

springboot启动原理分析

上面的 SpringFactoriesLoader.loadFactoryNames() ,是从 META-INF/spring.factories 的资源文件中,读取 key 为org.springframework.context.ApplicationContextInitializer 的 value。

springboot启动原理分析

而 spring.factories 的部分内容如下:

springboot启动原理分析

2)、setInitializers():

所以,这里 setInitializers() 所得到的成员变量 initializers 就被初始化为ConfigurationWarningsApplicationContextInitializer,ContextIdApplicationContextInitializer,DelegatingApplicationContextInitializer,ServerPortInfoApplicationContextInitializer 这四个类的对象组成的 list。

3、初始化 classpath 下的所有的可用的 ApplicationListener

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)):

1)、getSpringFactoriesInstances()

和上面的类似,但是它是从 META-INF/spring.factories 的资源文件中,获取到 key 为 org.springframework.context.ApplicationListener 的 value。

springboot启动原理分析

2)、setListeners():

springboot启动原理分析

所以,这里 setListeners() 所得到的成员变量 listeners 就被初始化为 ClearCachesApplicationListener,ParentContextCloserApplicationListener,FileEncodingApplicationListener,AnsiOutputApplicationListener ,ConfigFileApplicationListener,DelegatingApplicationListener,ClasspathLoggingApplicationListener,LoggingApplicationListener,LiquibaseServiceLocatorApplicationListener 这九个类的对象组成的 list。

4、deduceMainApplicationClass() :根据调用栈,推断出 main 方法的类名

springboot启动原理分析

二、run 方法解析

springboot启动原理分析

上面看完了构造方法后,已经初始化了一个 SpringApplication 对象,接下来调用其 run 方法,代码如下:

springboot启动原理分析

可变个数参数 args 即是我们整个应用程序的入口 main 方法的参数。StopWatch 是来自 org.springframework.util 的工具类,可以用来方便的记录程序的运行时间。

1、configureHeadlessProperty():设置 headless 模式

Headless模式是系统的一种配置模式。在该模式下,系统缺少了显示设备、键盘或鼠标。
Headless模式虽然不是我们愿意见到的,但事实上我们却常常需要在该模式下工作,尤其是服务器端程序开发者。因为服务器(如提供Web服务的主机)往往可能缺少前述设备,但又需要使用他们提供的功能,生成相应的数据,以提供给客户端(如浏览器所在的配有相关的显示设备、键盘和鼠标的主机)。

实际上是就是设置系统属性 java.awt.headless,该属性会被设置为 true。(System.setProperty("java.awt.headless", "true");)

2、getRunListeners():加载 SpringApplicationRunListener 对象

springboot启动原理分析

上面的 getRunListeners() 中也利用 SpringFactoriesLoader 加载 META-INF/spring.factories 中 key 为 SpringApplicationRunListener 的值,然后再将获取到的值作为参数传递到 SpringApplicationRunListeners 的构造方法中去创建对象。

3、new DefaultApplicationArguments(args) :获取启动时传入参数 args(main 方法传进来的参数) 并初始化为 ApplicationArguments 对象。

4、prepareEnvironment(listeners, applicationArguments):根据 listeners 和 applicationArguments 配置SpringBoot 应用的环境。

springboot启动原理分析

5、configureIgnoreBeanInfo(environment):根据环境信息配置要忽略的 bean 信息

6、printBanner(environment):打印标志。

7、createApplicationContext():根据应用类型来确定该 Spring Boot 项目应该创建什么类型的 ApplicationContext ,默认情况下,如果没有明确设置的应用程序上下文或应用程序上下文类,该方法会在返回合适的默认值。

springboot启动原理分析

8、exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context)

获取异常,这里也是通过 SpringFactoriesLoader 加载 META-INF/spring.factories 中 key 为 SpringBootExceptionReporter 的全类名的 value 值。

9、prepareContext(context, environment, listeners, applicationArguments, printedBanner):完成整个容器的创建与启动以及 bean 的注入功能。

springboot启动原理分析

1)、postProcessApplicationContext(context)

该方法对 context 进行了预设置,设置了 ResourceLoader 和 ClassLoader,并向 bean 工厂中添加了一个beanNameGenerator 。

2)、applyInitializers(context)

在刷新之前将任何 ApplicationContextInitializer 应用于上下文

3)、load(context, sources.toArray(new Object[0]))

springboot启动原理分析

主要是加载各种 beans 到 ApplicationContext 对象中。

(1)、getBeanDefinitionRegistry(context)

获取 bean 定义注册表

(2)、createBeanDefinitionLoader()

通过 BeanDefinitionLoader 的构造方法把参数(注册表、资源)传进去,然后创建 BeanDefinitionLoader。

(3)、load()

把资源全部加载。

10、refreshContext(context)

refreshContext(context) 方法又调用了 refresh(context)。在调用了 refresh(context) 方法之后,调用了 registerShutdownHook 方法:

springboot启动原理分析

进入refresh方法:可以从注释看到,正在做各种初始化工作

springboot启动原理分析

进入onRefresh() 方法,查找它的父类ReactiveWebServerApplicationContext 的实现,可以看到此时正在创建web容器,先判断是否存在本地的容器,然后再使用自动配置的容器,以tomcat为例,进入TomcatReactiveWebServerFactory:

springboot启动原理分析springboot启动原理分析

springboot启动原理分析

方法 finishBeanFactoryInitialization(beanFactory)进行了非懒加载 beans 的初始化工作。

11、afterRefresh(context, applicationArguments):在上下文刷新后调用该方法,其内部没有做任何操作。

12、输出日志记录执行主类名、时间信息

springboot启动原理分析

13、发布应用上下文启动完成事件

listeners.started(context);

触发所有 SpringApplicationRunListener 监听器的 started 事件方法。

14、执行所有 Runner 运行器

springboot启动原理分析

执行所有 ApplicationRunner 和 CommandLineRunner 这两种运行器。

15、发布应用上下文就绪事件

listeners.running(context);

触发所有 SpringApplicationRunListener 监听器的 running 事件方法。

16、返回应用上下文

return context;