SpringBoot项目的mian函数
@SpringBootApplication
public class SpringBootMyTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootMyTestApplication.class, args);
}
}
进入run主方法中,
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
// 两件事:1.初始化SpringApplication 2.执行run方法
return new SpringApplication(primarySources).run(args);
}
好了,带你进入正题。
SpringApplication 实例化过程,首先是进入带参数的构造方法,最终回来到两个参数的构造方法:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//将primarySources数组转换为List,最后放到LinkedHashSet集合中
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//【1.1 推断应用类型,后面会根据类型初始化对应的环境。常用的一般都是servlet环境 】
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//【1.2 初始化classpath下 META-INF/spring.factories中已配置的ApplicationContextInitializer 】
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//【1.3 初始化classpath下所有已配置的 ApplicationListener 】
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//【1.4 根据调用栈,推断出 main 方法的类名 】
this.mainApplicationClass = deduceMainApplicationClass();
}
1. 推断应用类型
点击进入WebApplicationType.deduceFromClassPath()方法:
static WebApplicationType deduceFromClasspath() {
//classpath下必须存在org.springframework.web.reactive.DispatcherHandler
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;
}
}
//classpath环境下存在javax.servlet.Servlet或者org.springframework.web.context.ConfigurableWebApplicationContext
return WebApplicationType.SERVLET;
}
因为项目中引入了Web的依赖,所以是一个Web项目,这个地方最终返回的是SERVLET,这个也是最常用的类型。
2. 初始化ApplicationContextInitializer
从图中可以看出,最终初始化了7个ApplicationContextInitializer,而且这个7个对象是从classpath下 META-INF/spring.factories中获取,验证一下,进入getSpringFactoriesInstances方法:
查询配置:
这样也就找到了初始化是获取的7个ApplicationContextInitializer的配置。ApplicationContextInitializer 是Spring框架的类, 这个类的主要目的就是在ConfigurableApplicationContext 调用refresh()方法之前,回调这个类的initialize方法。通过 ConfigurableApplicationContext 的实例获取容器的环境Environment,从而实现对配置文件的修改完善等工作。
3. 初始化ApplicationListener
和上面ApplicationContextInitializer的初始化同理,也是在classpath下META-INF/spring.factories中获取,验证一下:
一共是11个,从META-INF/spring.factories中找一下:
刚好11个,这也验证了ApplicationListener的初始化过程。
4. 推断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;
}
从图中可以看出,这个也就是我们通常定义的启动类。