SpringApplication 初始化过程
# 670.SpringApplication 初始化过程
讲讲 SpringBoot 初始化的过程,主要是环境和 IoC 容器的初始化
# 断点调试
老规矩,从打断点开始,一步步 debug。例如我们使用 LearnSpringBoot-Web-Admin 工程:
我们步入:
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
1
2
3
2
3
可以看到,第一步是先创建了 Spring 应用,然后在调用 run
然后我们看其构造方法:
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
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));
this.mainApplicationClass = deduceMainApplicationClass();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
可以看到,说下保存了主类的一些信息(第 8 行)
然后判断并保存应用类型的信息(第 9 行):会调用工具类 ClassUtils,来判断是否 Reactive,我们并没有使用,所以这里返回的是 Servlet
static WebApplicationType deduceFromClasspath() {
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
下一步就是执行 getSpringFactoriesInstances
方法:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
该方法就是读取 spring.factories 文件里的信息的,然后读取文件里有无配置 ApplicationContextInitializer
,有则读取出来后保存,
例如 spring-boot-2.3.4.RELEASE.jar!\META-INF\spring.factories 文件的配置:
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
1
2
3
4
5
6
2
3
4
5
6
debug 也可以看到,确实有加载该文件的 Initializer:
在然后就是读取监听器:
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
1
其原理也是一样,读取 spring.factories 里配置的监听器,然后保存
下一步就是找出主程序类并启动了:
this.mainApplicationClass = deduceMainApplicationClass();
1
其实就是判断方法名是否为 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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
总得来说,创建的过程就是读取一些配置信息并保存到 ApplicationContext,然后启动
上次更新: 2024/10/3 10:01:52