Spring Boot 2.1.1.RELEASE Main方法启动详解一
一、SpringApplication(ResourceLoader, Class<?>...)分析:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// resourceLoader 默认为空(null)
this.resourceLoader = resourceLoader;
// main方法中的args参数,可接收命令行启动时添加的参数
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 1.根据classpath下是否有相应的类确定Spring容器类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 2.加载ApplicationContextInitializer初始化类
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 3.加载ApplicationListener监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 4.推断main方法所在的类
this.mainApplicationClass = deduceMainApplicationClass();
}
1.1 确定Spring容器类型
static WebApplicationType deduceFromClasspath() {
// 1.确定reactive容器类型
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
// 2.确定none容器类型
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
// 3.默认servlet容器类型
return WebApplicationType.SERVLET;
}
分析:
- 判断,如果能加载org.springframework.web.reactive.DispatcherHandler,并且不能加载org.springframework.web.servlet.DispatcherServlet和org.glassfish.jersey.servlet.ServletContainer,那么判断这个容器类型为WebApplicationType.REACTIVE
- 判断,如果不能加载javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext,那么判断这个容器类型为WebApplicationType.NONE
- 如果前面都没加载,那么容器类型为默认的WebApplicationType.SERVLET
1.2 加载ApplicationContextInitializer初始化类
public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<>();
// 添加ApplicationContextInitializer类
this.initializers.addAll(initializers);
}
分析:
通过SpringFactoriesLoader.loadFactoryNames(type, classLoader)加载类名,使用ClassUtils.forName(name, classLoader)加载类对象,并获取构造Constructor方法,使用BeanUtils.instantiateClass(constructor, args)实例化对象,使用AnnotationAwareOrderComparator.sort(instances)进行排序,
他们分别是:
- ConfigurationWarningsApplicationContextInitializer
- ContextIdApplicationContextInitializer
- ConditionEvaluationReportLoggingListener
- SharedMetadataReaderFactoryContextInitializer
- ServerPortInfoApplicationContextInitializer
- DelegatingApplicationContextInitializer
1.3 加载ApplicationListener监听器
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
this.listeners = new ArrayList<>();
// 添加ApplicationListener类
this.listeners.addAll(listeners);
}
分析:
通过SpringFactoriesLoader.loadFactoryNames(type, classLoader)加载类名,使用ClassUtils.forName(name, classLoader)加载类对象,并获取构造Constructor方法,使用BeanUtils.instantiateClass(constructor, args)实例化对象,使用AnnotationAwareOrderComparator.sort(instances)进行排序,
他们分别是:
- BackgroundPreinitializer
- ClearCachesApplicationListener
- ParentContextCloserApplicationListener
- FileEncodingApplicationListener
- AnsiOutputApplicationListener
- ConfigFileApplicationListener
- DelegatingApplicationListener
- ClasspathLoggingApplicationListener
- LoggingApplicationListener
- LiquibaseServiceLocatorApplicationListener
1.4 获取main方法所在类
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
// 遍历所有执行过的栈信息,查找到其方法名为mian的栈信息,并返回其类信息
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
} catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
分析:
通过异常获取当前线程的堆栈信息,遍历获取方法名为main的堆栈对应的class信息
注:上面加载类名的读取路径是:/META-INF/spring.factories
上一篇: springboot2 添加启动类
下一篇: Python+Pycharm踩坑