前言
还是从SpringBoot的启动类说起,这篇文章主要分析启动类中的SpringApplication
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
可以看出main函数中重要的就是SpringApplication.run()
,这可以分为两部分来探讨:
- SpringApplication的构造过程
- SpringApplication的run()方法
SpringApplication的初始化
首先进入SpringApplication的构造函数,先是单个参数的构造方法,后进入两个参数的构造方法,ResourceLoader是Spring的资源加载器,这里没有自定义的ResourceLoader传入,所以为NULL,而primarySources参数就是我们传入的Application.class启动类
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));
//1. 推断应用类型
this.webApplicationType = deduceWebApplicationType();
//2. initializer初始化模块,加载ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//3. 加载监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//4. 配置应用main方法所在的类
this.mainApplicationClass = deduceMainApplicationClass();
}
SpringApplication的初始化主要包括以下4个步骤:
- 推断应用类型
- 加载初始化构造器ApplicationContextInitializer
- 创建应用监听器
- 设置应用main()方法所在的类
1. 推断应用类型
this.webEnvironment=deduceWebApplicationType(); 判断应用的类型,是否是servlet应用还是reactive应用或者是none,webEnvironment中定义了这三种类型
2. 加载初始化构造器ApplicationContextInitializer
setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class)): 通过SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer
进入loadFactoryNames方法,然后进入loadSpringFactories方法,获取当前ClassLoader下的所有META-INF/spring.factories文件的配置信息
而后通过loadSpringFactories(classloader).getOrDefault(factoryClassName,Collections.emptyList()) 从所有META-INF/spring.factories文件的配置信息的map中获取指定的factory的值
默认情况下,从 spring.factories 文件找出的 key 为 ApplicationContextInitializer 的类有如上图中所示4种
对于 ApplicationContextInitializer,它是应用程序初始化器,做一些初始化工作
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
/**
* Initialize the given application context.
* @param applicationContext the application to configure
*/
void initialize(C applicationContext);
}
3. 创建应用监听器
setListeners()方法与setInitializers()方法类似,只不过它是使用SpringFactoriesLoader在应用的classpath的META-INT/spring.factories中查找并加载所有可用的ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
ApplicationListener,应用程序事件(ApplicationEvent)监听器:
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}
更详细的分析可以参阅我之前的文章: springboot系列文章之启动时初始化数据
4. 设置应用main()方法所在的类
在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