SpringBoot启动原理
参考1:Spring Boot的启动过程三:SpringApplication.run()
参考2:面试官问我,SpringApplication.run做了哪些事?

如何启动一个SpringBoot应用?

1
2
3
4
5
6
public class Test{
public static void main(String[] args){
SpringApplication springApplication = new SpringApplication(Test.class);
springApplication.run(args);
}
}

解析创建SpringApplication对象

源码1

SpringApplication构造方法:

1
2
3
public SpringApplication(Object... sources) {
initialize(sources);
}

源码2(initialize(…))

初始化SpringAppcation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void initialize(Object[] sources) {
//保存主配置类
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
//判断当前应用是否为WEB应用
this.webEnvironment = deduceWebEnvironment();
//通过类路径META-INF/spring.factories文件获取ApplicationContextInitializer类型的实例,并保存
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//通过类路径META-INF/spring.factories文件获取ApplicationListener类型的实例,并保存
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//从多个配置类中找到有main方法的主配置类
this.mainApplicationClass = deduceMainApplicationClass();
}

源码3 getSpringFactoriesInstances(…)

获取通过META-INF/spring.factories文件获取到的对应的类路径下的实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//通过类路径META-INF/spring.factories文件获取ApplicationContextInitializer类型的实例
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}

private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
//通过类路径META-INF/spring.factories文件获取ApplicationContextInitializer.class类型的类名
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//获取实例
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

源码4(deduceMainApplicationClass())

从运行类的堆栈中获取含有main方法的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//从运行类的堆栈中获取含有main方法的类
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;
}

解析springApplication.run(args)

源码1(run(…))

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
public ConfigurableApplicationContext run(String... args) {
//跑马灯对象--用于记录运行时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
//通过META-INF/spring.factories获取SpringApplicationRunListener类型的实例
SpringApplicationRunListeners listeners = getRunListeners(args);
//遍历回调SpringApplicationRunListener的starting方法--既启动监听器
listeners.starting();
try {
//封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//环境准备,完成后遍历回调SpringApplicationRunListener的environmentPrepared方法对监听器配置环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//打印Banner-既控制台显示的Spring....
Banner printedBanner = printBanner(environment);
//根据创建的环境判断,是创建web容器,还是普通的IOC容器
context = createApplicationContext();
//注册异常分析器
analyzers = new FailureAnalyzers(context);
//准备上下文
//遍历回调ApplicationContextInitializer的initialize事件
//遍历回调SpringApplicationRunListeners中的contextPrepared事件
//环境准备完成之后,遍历回调SpringApplicationRunListeners中的contextLoaded事件
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//刷新上下文,初始化所有自动配置类
refreshContext(context);
//遍历所有注册的ApplicationRunner和CommandLineRunner,并执行其run()方法
afterRefresh(context, applicationArguments);
//调用所有的SpringApplicationRunListener的finished()方法,广播SpringBoot已经完成了ApplicationContext初始化的全部过程
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}

源码2(getRunListeners(…))

通过类路径META-INF/spring.factories文件获取ApplicationContextInitializer类型的实例,并将其封装到SpringApplicationRunListeners实例

1
2
3
4
5
6
7
//创建实例 SpringApplicationRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
//通过META-INF/spring.factories获取SpringApplicationRunListener类型的实例
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}

源码3(prepareEnvironment(…))

准备环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//准备环境
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
//创建环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
//配置环境
configureEnvironment(environment, applicationArguments.getSourceArgs());
//遍历回调SpringApplicationRunListener的environmentPrepared方法
listeners.environmentPrepared(environment);
if (!this.webEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
return environment;
}

源码4(createApplicationContext())

根据创建的环境判断,是创建web容器,还是普通的IOC容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//根据创建的环境判断,是创建web容器,还是普通的IOC容器
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
contextClass = Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}

源码5(prepareContext(…))

准备上下文

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
//准备上下文
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//设置环境
context.setEnvironment(environment);
postProcessApplicationContext(context);
//遍历回调ApplicationContextInitializer的initialize事件--即上下文注入并初始化
applyInitializers(context);
//遍历回调SpringApplicationRunListeners中的contextPrepared事件--即上下注入
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}

// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}

// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
//遍历回调SpringApplicationRunListeners中的contextLoaded事件--即加载上下文
listeners.contextLoaded(context);
}

综上,SpringApplication.run()总共做了两件是:

  1. 创建了SpringApplication对象,初始化的时候,判断是否为WEB应用,并将通过配置文件META-INF/spring.factories找到对应的上下文类路径和监听器路径,将其实例化并且保存起来。
  2. 运行run方法,通过配置文件META-INF/spring.factories找到对应的监听器路径,将其实例化并启动。创建环境和创建上下文,并为监听器配置。刷新上下文,然后调用所有的监听器的finished()方法,广播SpringBoot已经完成了。

最后更新: 2019年10月12日 20:21

原始链接: https://maiyikai.github.io/2019/03/22/1553480412/

× ~谢谢大爷~
打赏二维码