SpringApplication类提供了一种方便的方法来引导从main()方法开始的Spring应用程序。在许多情况下,你可以委托给静态SpringApplication.run方法

1
2
3
4
5
6
7
8
@SpringBootApplication
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

}

本文主要根据对SpringApplication类的源码阅读来了解SpringApplication的启动流程。

  1. 启动StopWatch用于记录应用启动时长
  2. 配置headless属性(AWT 相关属性)
  3. 获取应用监听器SpringApplicationRunListeners并启动
  4. 初始化ApplicationArguments(提供对用于运行 SpringApplication 的参数的访问)
  5. 初始化ConfigurableEnvironment(加载所有的 environment,包括 application.properties/application.yml 以及其他外部的属性配置 )
  6. 打印Banner
  7. 创建应用上下文ApplicationContext
  8. 初始化exceptionReporters(记录启动过程中的异常信息)
  9. 准备 ApplicationContext 对象,初始化一些属性
  10. 启动(刷新)Spring 容器
  11. 执行 Spring 容器的初始化的后置逻辑
  12. 结束StopWatch统计
  13. 通知监听器,Spring 容器启动完成
  14. 调用 ApplicationRunner,CommandLineRunner 的 run 方法
  15. 通知监听器,Spring 容器正在运行

构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}

public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
/* 初始化资源加载器 */
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
/* 初始化 primarySources */
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
/* 获取 web 应用的类型 */
this.webApplicationType = WebApplicationType.deduceFromClasspath();
/* 初始化 initializers(ApplicationContextInitializer 类型的 bean) */
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
/* 初始化 setListeners(ApplicationListener 类型的 bean) */
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
/* 推断 main 方法 Application 的 Class */
this.mainApplicationClass = deduceMainApplicationClass();
}

deduceFromClasspath

通过检查 classpath 推断出当前 web 环境

1
2
3
4
5
6
7
8
9
10
11
12
13
static WebApplicationType deduceFromClasspath() {
/* 判断是否存在是否是 webflux */
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}

deduceMainApplicationClass

推断是哪个类调用了 main 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {

}
return null;
}

getSpringFactoriesInstances

根据给定的 class 类型,获取对应 factories 中的实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
/* 获取类加载器 */
ClassLoader classLoader = getClassLoader();
/* Set 类型的 names 确保惟一,以防止重复 */
/* 加载 `META-INF/spring.factories` 里的 class */
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
/* 为他们创建实例 */
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
/* 为他们进行排序 */
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

run方法

运行 Spring 应用

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
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}

public ConfigurableApplicationContext run(String... args) {
/* stopWatch 对象,用于统计指定任务的运行时间 */
StopWatch stopWatch = new StopWatch();
/* 开始 stopWatch 统计 */
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
/* 配置 headless 属性 */
configureHeadlessProperty();
/* 获取 SpringApplicationRunListener 类型的 bean 实例列表 */
SpringApplicationRunListeners listeners = getRunListeners(args);
/* 启动监听器 */
listeners.starting();
try {
/* 创建默认 applicationArguments,提供对用于运行 SpringApplication 的参数的访问。*/
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
/* 加载所有的 environment,包括 application.properties/application.yml 以及其他外部的属性配置 */
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
/* 打印 banner 信息 */
Banner printedBanner = printBanner(environment);
/* 创建应用上下文 */
context = createApplicationContext();
/* 创建异常报告器 */
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
/* 初始化 Spring 容器。 */
refreshContext(context);
/* 执行 Spring 容器的初始化的后置逻辑 */
afterRefresh(context, applicationArguments);
/* 停止 stopWatch 统计 */
stopWatch.stop();
/* 打印 Spring Boot 启动日志。 */
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
/* 通知 SpringApplicationRunListener,Spring 容器启动完成。 */
listeners.started(context);
/* 调用 ApplicationRunner 或者 CommandLineRunner 的运行方法。 */
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
/* 如果发生异常,则进行处理,并抛出 IllegalStateException 异常 */
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
/* SpringApplicationRunListener 的数组,Spring 容器运行中。 */
try {
listeners.running(context);
}
catch (Throwable ex) {
/* 如果发生异常,则进行处理,并抛出 IllegalStateException 异常 */
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}

prepareEnvironment

准备 environment,加载属性配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
/* 创建并配置 ConfigurableEnvironment 对象*/
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
/* 通知 SpringApplicationRunListeners,环境变量已经准备完成。 */
listeners.environmentPrepared(environment);
/* 绑定 environment 到 SpringApplication */
bindToSpringApplication(environment);
/* 如果非自定义 environment ,则根据条件转换 */
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
/* 如果有 attach 到 environment 上的 MutablePropertySources ,则添加到 environment 的 PropertySource 中。 */
ConfigurationPropertySources.attach(environment);
return environment;
}

createApplicationContext

创建应用上下文

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
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
/* web 应用环境,AnnotationConfigServletWebServerApplicationContext */
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
/* webflux 应用环境,AnnotationConfigReactiveWebServerApplicationContext */
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
/* 非 web 应用环境,AnnotationConfigApplicationContext */
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
/* 返回对应应用上下文实例 */
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

prepareContext

准备 ApplicationContext 对象,初始化它的一些属性

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
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
/* 设置 context 的 environment 属性 */
context.setEnvironment(environment);
/* 设置 context 的一些属性 */
postProcessApplicationContext(context);
/* 初始化 ApplicationContextInitializer */
applyInitializers(context);
/* 通知 SpringApplicationRunListeners,Spring 容器准备完成。 */
listeners.contextPrepared(context);
/* 打印日志 */
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
/* 获取 beanFactory */
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
/* 注册单例 springApplicationArguments bean */
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
/* 注册单例 printedBanner bean */
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
/* 加载 BeanDefinition */
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
/* 通知 SpringApplicationRunListeners,Spring 容器加载完成。 */
listeners.contextLoaded(context);
}

callRunners

调用 ApplicationRunner 或者 CommandLineRunner 的 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
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
/* 获取所有的 ApplicationRunner 类型的 bean 加入到 runners */
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
/* 获取所有的 CommandLineRunner 类型的 bean 加入到 runners */
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
/* 排序 runners */
AnnotationAwareOrderComparator.sort(runners);
/* LinkedHashSet 去重并遍历 */
for (Object runner : new LinkedHashSet<>(runners)) {
/* ApplicationRunner 类型 runner */
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
/* CommandLineRunner 类型 runner */
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}

private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
try {
(runner).run(args);
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
}
}

private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
try {
(runner).run(args.getSourceArgs());
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
}
}