一、概述
SpringApplication初始化阶段属于运行前的准备阶段,大多数Spring Boot应用直接或间接的使用SpringApplication API驱动Spring应用,SpringApplication允许指定应用的类型,大体上包括Web应用和非Web应用。从Spring Boot 2.0开始,Web应用又可以分为Servlet Web,Reactive Web。
当然Spring Application也可以调整Banner输出、配置默认属性的内容等。这些状态的变更操作只要在run()方法之前指定即可。简单来说,SpringApplication的准备阶段主要有两阶段完成:
- 构造阶段
- 配置阶段
二、SpringApplication 构造阶段
(1) 构造过程
(2) 源码解析
以最简单应用代码为例:
@SpringBootApplication
public class SimpleApplication {
// 1.引导类 SimpleApplication.main()
public static void main(String[] args) {
// 2.执行SpringApplication.run()
SpringApplication.run(SimpleApplication.class, args);
}
}
public class SpringApplication {
// 3.构建SpringApplication
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 4.推断Web应用类型
this.webApplicationType = deduceWebApplicationType();
// 5.加载Spring应用上下文初始化器(ApplicationContextInitialzer)
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 6.加载Spring应用事件监听器(ApplicationListener)
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 7.推断应用引导类
this.mainApplicationClass = deduceMainApplicationClass();
}
}
(3) 推断web应用类型
web应用类型判断依据:
- DispatcherHandler
- DispatcherServlet
- Servlet
- ConfigurableWebApplicationContext
(3.1) 当DispatcherHandler存在,且DispatcherServlet 不存在时,换言之SpringBoot仅仅依赖WebFlux存在时,此时的web应用类型为Reactive Web, 即WebApplicationType.REACTIVE;
(3.2) 当Servlet和ConfigurableWebApplicationContext均不存在时,当前应用为非Web应用,WebApplicationType.NONE;
(3.3) 当Spring WebFlux 和Spring Web MVC同时存在时,Web应用类型同样是Servlet,即WebApplicationType.SERVLET;
源码实现:
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
+ "web.reactive.DispatcherHandler";
private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."
+ "web.servlet.DispatcherServlet";
+
private WebApplicationType deduceWebApplicationType() {
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
(4)加载Spring应用上下文初始化器 - ApplicationContextInitializer
Spring应用上行文的初始化器,主要通过Spring工厂加载机制来加载,即调用SpringFactoriesLoader.loadFactoryNames(type, classLoader)),将返回META-INF/spring.factories资源配置的ApplicationContextInitializer实现名单,例org.spring.framework.boot:spring-boot:2.0.2.RELEASE中的内容:
#Application Context Initializers
org.springframework.context.ApplicationContextInitializer=
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,
org.springframework.boot.context.ContextIdApplicationContextInitializer,
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
...
// 1.加载Spring应用上下文初始化器
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
...
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
// 2.通过Spring工厂加载机制 查找ApplicationContextInitializer实现
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
// 3. 构建ApplicationContextInitializer对象实例
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
(5)加载Spring应用事件监听器 - ApplicationListener
Spring应用事件监听器加载过程与(4)中应用初始化器的加载过程类似,也是通过spring工厂加载机制加载META-INF/spring.factories文件中配置的ApplicationListener:
#Application Listeners
org.springframework.context.ApplicationListener=
org.springframework.boot.ClearCachesApplicationListener,
org.springframework.boot.builder.ParentContextCloserApplicationListener,
org.springframework.boot.context.FileEncodingApplicationListener,
org.springframework.boot.context.config.AnsiOutputApplicationListener,
org.springframework.boot.context.config.ConfigFileApplicationListener,
org.springframework.boot.context.config.DelegatingApplicationListener,
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,
org.springframework.boot.context.logging.LoggingApplicationListener,
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
源码解析:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
...
// 1.加载Spring应用事件监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
...
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
// 2.通过Spring工厂加载机制 查找ApplicationListener实现
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// 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;
}
// 3. 构建ApplicationListener对象实例
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
(6)推断应用引导类
推断应用引导类是SpringApplication构造过程的末尾动作:
// 根据当前线程栈来判断其栈中哪个类包含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;
}