个人学习SpringBoot 之main方法推断和应用类型推断
在SpringApplication初始化的时候我们可以看到这么一段代码
/**
* Create a new {@link SpringApplication} instance. The application context will load
* beans from the specified primary sources (see {@link SpringApplication class-level}
* documentation for details. The instance can be customized before calling
* {@link #run(String...)}.
* @param resourceLoader the resource loader to use
* @param primarySources the primary bean sources
* @see #run(Class, String[])
* @see #setSources(Set)
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
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 = deduceWebApplicationType();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
其中我们看到了deduceWebApplicationType()和deduceMainApplicationClass()这两个方法,其中前者就是应用类型推断方法,后者是main方法推断,下面我们就一起来看下这两者的实现
首先是推断应用类型
private WebApplicationType deduceWebApplicationType() {
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
这段代码很清楚,可以看到其实逻辑很清楚如果class
REACTIVE_WEB_ENVIRONMENT_CLASS可加载被加载到内存,MVC_WEB_ENVIRONMENT_CLASS,JERSEY_WEB_ENVIRONMENT_CLASS不可被加载到内存,那么就返回reactive应用类型,接着去遍历WEB_ENVIRONMENT_CLASSES里面的类型判断都不可加载内存的话就返回none,最后返回SERVLET类型。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;
}
正如代码所示它是通过堆栈信息去判断的不是直接去加载传入的class类,至于为什么这样做我也不是很明白,有明白的大佬,欢迎留言指教下,下面我们来debug下来实际的看下
这便是SpringApplication的main方法推断并且根据结果加载class
个人语文表达能力有限,还望大佬指教
参考书籍: SpringBoot 编程思想