SpringBoot启动过程-run()

SpringApplication.run()

在上一篇中,我们分析了 SpringBoot 启动过程中的 @SpringBootApplocation ,其主要功能就是加载对应的 @ConfigurationAuto Configure 模块中的组件信息,并将组件内容加入到容器中。

这篇将开始分析 SpringBoot 的启动过程,而启动过程中最核心的两个部分就是 SpringApplication 的启动过程SpringApplication 的 run 方法 ,下面为分析过程:

SpringApplication 的构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
...
// 设置启动的源Class,即启动的SpringBootLearningApplication.class对象,包含了对应的 classLoader
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));

// 设置了 webApplication的类型,尚未配置web,所以当前为 NONE (Servlet, Reactive)
this.webApplicationType = WebApplicationType.deduceFromClasspath();

// 借助 SpringFactoriesLoader 找到 /META-INF/spring.factories 下的所有配置 key 为 ApplicationContextInitializer
(所有的应用初始化器),实例化并设置到 setInitializers 这个集合属性中
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));

// 和上面一样, 通过 SpringFactoriesLoader 找到所有配置 key 为 ApplicationListener (所有的应用程序监听器),
实例化并设置到 setListeners 集合属性中
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));

// 找到 StackTrace (方法调用堆栈)中的 main 方法,即入口类的名字,并 Class.forName 得到类对象
this.mainApplicationClass = this.deduceMainApplicationClass();
}


ApplicationEvent

SpringBoot 中使用了很多 Event 去响应容器状态,而 ApplicationEvent 为多个组件 bean 提供了消息通信的支持,其中就包括了接下来在 run( ) 使用到的 SpringApplicationEvent ,它实现了全局的 base ApplicationEvent,并扩展为多个 Spring 启动中的事件 Event,如下:

  1. ApplicationContextInitializedEvent
  2. ApplicationEnvironmentPreparedEvent
  3. ApplicationPreparedEvent
  4. ApplicationStartedEvent
  5. ApplicationReadyEvent
  6. ApplicationFailedEvent
  7. ApplicationStartingEvent


事件的传递过程如下:

  1. SpringApplicationRunListener 调用对应的操作如 ( starting, running, contextLoad… )
  2. SpringApplicationRunListener 内部针对不同的事件,遍历内部集合调用对应的方法,具体实现类为 EventPublishingRunListener 调用
  3. EventPublishingRunListener 将对应的操作 ( starting, environmentPrepared.. ) 封装成对应的事件并通过属性 initialMulticaster push 广播出去
  4. 最后广播出去的事件如 ( ApplicationStartingEvent ) 会被 SpringApplication 中的 listeners 属性监听处理


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// SpringApplication.class
public ConfigurableApplicationContext run(String... args) {
listeners.starting();
}

// SpringApplicationRunListeners
public void starting() {
Iterator var1 = this.listeners.iterator();

while(var1.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();
listener.starting();
}
}

// EventPublishingRunListeners.class
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}


EventPublishingRunListener 具体操作事件的广播推送如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 // EventPublishingRunListener 事件推送监听器

// Spring 启动, run()的时候立即运行,ApplicationStartingEvent
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}

// 环境信息准备好并准备创建 ApplicationContext 之前, ApplicationEnvironmentPreparedEvent
public void environmentPrepared(ConfigurableEnvironment environment) {
}

//ApplicationContext 创建完成,并准备加载 source时调用, ApplicationPreparedEvent
public void contextPrepared(ConfigurableApplicationContext context) {
}

// ApplicationContext 已经创建并加载,在 refresh() 之前调用, ApplicationPreparedEvent
public void contextLoaded(ConfigurableApplicationContext context) {
}

// Application refresh()后,容器正式启动, ApplicationStartedEvent
public void started(ConfigurableApplicationContext context) {
}

// Spring 正式运行, ApplicationReadyEvent
public void running(ConfigurableApplicationContext context) {
}

// 当运行失败时, ApplicationFailedEvent
public void failed(ConfigurableApplicationContext context, Throwable exception) {
}


SpringApplication.run()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
public ConfigurableApplicationContext run(String... args) {
// 启动 StopWatch,开始记录任务的执行时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();

// 定义 context
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();

// 配置 System Property java.awt.headless = true,用于控制台下的调试
this.configureHeadlessProperty();

// 获取 SpringApplicationRunListeners,实例为 EventPublishingRunListener
SpringApplicationRunListeners listeners = this.getRunListeners(args);

// 封装SpringApplicationEvent,即 ApplicationStartingEvent 进行广播推送
listeners.starting();

// 定义异常集合,用后于catch && handle
Collection exceptionReporters;
try {

// 创建应用程序参数类
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

// 根据 WebType 创建 对应的 Environment 对象,用于获取 properties,profile
// 同时EventPublishingRunListeners 广播 ApplicationEnvironmentPreparedEvent
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);

// 在 Environment对象中配置需要忽略的 bean 信息
this.configureIgnoreBeanInfo(environment);

// 打印 banner
Banner printedBanner = this.printBanner(environment);

// 创建 ApplicationContext (AnnotationConfigApplicationContext)
// 通过 WebType 得到对应的 ApplicationContextClass,通过反射的到对应的ApplicationContext
context = this.createApplicationContext();

// 通过 SpringFactoriesLoader 获取配置key的 SpringBoot异常报告器
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);

// ApplicationContext pre handle
// 1.为Context 设置 environment
// 2.为之前加载的 AppplicationInitializers 遍历 initialize(context),进行上下文初始化
// 3.创建SpringDefinitionLoader,用于加载 xml 或 JavaConfig 中的bean
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);

// 刷新应用上下文 ApplicationContext
this.refreshContext(context);

// 刷新上下文后的额外操作
this.afterRefresh(context, applicationArguments);

// 停止时间计时
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}

// 启动加载的 listener list
listeners.started(context);

// 添加 ApplicationRunners 和 CommandLineRunners 相关的 Runners
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
// 这里用于处理之前捕获的异常集合
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}

try {
// 启动加载的 listener list
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}


总结:

启动 Spring Boot 的过程大致分为两部分,一部分为:SpringApplication 的构造过程SpringApplication.run() 具体的运行过程

SpringApplication 的构造方法主要有以下过程:

  1. 获取并设置 primarySources, 即程序的入口 Class
  2. 获取设置 webApplicationType
  3. 通过 SpringFactoriesLoader ,加载 spring.factories 中的 Initializers ,找到所有初始化器,并设置属性
  4. 同理,找到所有的应用程序监听器,并设置到 Listeners 属性中
  5. 找到运行的 main 主类,并设置到属性 mainApplicationClass

SpringApplication run() 的执行过程如下:

  1. 启动 StopWatch,开始记录任务的执行时间
  2. 定义 ApplicationContext,并通过 EventPublishingRunListeners 广播 ApplicationStartingEvent 事件,事件将会被加载的 listeners 监听并处理
  3. 创建应用参数类 ApplicationArguments 及根据 WebApplicationType 创建对应的 Environment,用于记录系统中的 Properties
  4. 创建 ApplicationContext
  5. 进行 prepareContext,对 context 设置environment,并遍历加载的 initializer 初始化 context,最后创建 SpringDefinitionLoader
  6. refreshContext,完成 bean 的解析,开启 processor 接口等工作
  7. 加载的 listeners 进行 start(), running(),同时加入 SpringRunners


参考

SpringBoot源码分析之SpringBoot的启动过程
Spring Boot 启动深究SpringApplication执行流程