上图为SpringBoot启动结构图,我们发现启动流程主要分为三个部分,第一部分进行SpringApplication的初始化模块,配置一些基本的环境变量、资源、构造器、监听器,第二部分实现了应用具体的启动方案,包括启动流程的监听模块、加载配置环境模块、及核心的创建上下文环境模块,第三部分是自动化配置模块,该模块作为springboot自动配置核心,在后面的分析中会详细讨论。在下面的启动程序中我们会串联起结构中的主要功能。
1、基于源码简单剖析SpringBoot的启动流程
Spring boot的启动过程:
SpringBoot应用启动后首先执行SpringBoot启动类的main方法中的public static ConfigurableApplicationContext run(Class<?> primarySource, String... args)
这个run方法,他又调用了重载方法的public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args)
,在这个run方法中调用了真正的run方法。
他们的调用关系如下图:
在调用正真干活的run方法之前,SpringAppication先进行了初始化:
最终真正干活的run方法
该方法中有几个关键的步骤:
(1)创建了应用监听器SpringApplicationRunListeners并开始监听 (2)加载SpringBoot配置环境ConfigurableEnvironment,如果是通过web容器发布,会加载StandardEnvironment,其最终也是继承了ConfigurableEnvironment,类图如下:
(3)将从配置文件中加载进来的配置环境(Enviroment)加入到监听器中 (4)创建应用配置上下文对象ConfigurableApplicationContext,我们可以到其具体的实现中看看:
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch(this.webApplicationType) {
case SERVLET:
contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
break;
case REACTIVE:
contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
break;
default:
contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
}
} catch (ClassNotFoundException var3) {
throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
}
}
return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}
(5)回到run方法继续往下走,prepareContext()方法将listeners、environment、applicationArguments、banner等组件与上下文对象关联 (6)调用refreshContext()方法是SpringBoot启动中最重要的一步,包括spring.factories的加载,bean的实例化等核心工作。这一步完成后SpringBoot的启动工作基本就完成了。下面是最终真正干活的refresh()方法的截图:
方法首先获取显式获取并设置了应用上下文(applicationContextClass),如果不存在,再根据不同的Web环境选择实例化不同的上下文对象,默认选择AnnotationConfigApplicationContext注解上下文(通过扫描所有注解类来加载bean),最后通过BeanUtils实例化上下文对象,并返回。
配置结束后,Springboot做了一些基本的收尾工作,返回了应用环境上下文。回顾整体流程,Springboot的启动,主要创建了配置环境(environment)、事件监听(listeners)、应用上下文(applicationContext),并基于以上条件,在容器中开始实例化我们需要的Bean,至此,通过SpringBoot启动的程序已经构造完成。
启动过程中的一些细节代码说明:
(1)在run方法一开始执行他就new了一个StopWatch,这个类有啥用呢?
开启单步调试,最终发现这个类的功能就是统计一下SpringBoot启动所用的时间并在最会在启动完成打印出来。
(2)在启动中有一个Banner,他的用处就是打印一下SpringBoot的logo