前言

‘SpringBoot启动流程源码分析第二篇之 SpringApplication.run(XXX.class, args); 做了什么’
此篇承接SpringBoot启动流程源码分析(一) 试图分析SpringBoot启动原理,本篇主要分析SpringApplication.run(XXX.class, args);到底做了什么

代码链路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 原始代码
SpringApplication.run(SpringbootStartApplication.class, args);
//run方法源码 org.springframework.boot.SpringApplication#run(java.lang.Class<?>, java.lang.String...)
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
// 重载run方法源码
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
// SpringApplication构造函数源码
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}

由此可以看出SpringApplication.run(SpringbootStartApplication.class, args);
等同于new SpringApplication(null,new Class[]{SpringbootStartApplication.class}).run(args);

构造方法

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 此处resourceLoader为null,primarySources为应用主类(SpringbootStartApplication.class)
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 验证赋值
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 获取应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 设置启动器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 设置应用状态监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断出mainClass
this.mainApplicationClass = deduceMainApplicationClass();
}

推断应用类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// org.springframework.boot.WebApplicationType#deduceFromClasspath
static WebApplicationType deduceFromClasspath() {
/*
存在org.springframework.web.reactive.DispatcherHandler
不存在org.springframework.web.servlet.DispatcherServlet
不存在org.glassfish.jersey.servlet.ServletContainer
说明类型为REACTIVE WEB
*/
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
/*
如果不存在javax.servlet.Servlet 或者 org.springframework.web.context.ConfigurableWebApplicationContext 说明为非WEB程序
*/
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
// 默认为SERVLET WEB
return WebApplicationType.SERVLET;
}

获取实现类(getSpringFactoriesInstances)

1
2
3
4
5
6
7
8
9
10
11
12
13
// org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>, java.lang.Class<?>[], java.lang.Object...)
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
// 获取自定义类加载器或者默认加载器
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
// 获取指定类在META-INF/spring.factories 配置文件下配置的实现类
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 加载类
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,classLoader, args, names);
// 排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

下面可以看一下配置文件中的详细配置信息

推断MainClass

创建一个异常,通过异常堆栈信息找到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) {
// Swallow and continue
}
return null;
}

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
public ConfigurableApplicationContext run(String... args) {
// 创建并启动计时监控类
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 初始化应用上下文和异常报告集合
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 配置java.awt.headless 参数,将参数设置默认为true
configureHeadlessProperty();
// 创建所有 Spring 运行监听器并发布应用启动事件 本质还是调用getSpringFactoriesInstances方法
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
// 初始化默认应用参数类
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 根据运行监听器和应用参数来准备 Spring 环境
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);
// 刷新应用上下文
refreshContext(context);
// 应用上下文刷新后置处理
afterRefresh(context, applicationArguments);
// 计时停止
stopWatch.stop();
if (this.logStartupInfo) {
// 输出日志记录执行主类名、时间信息
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// 发布启动完成事件
listeners.started(context);
// 执行所有 Runner 运行器
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}

try {
// 发布运行事件
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}