在上一篇中,提到主要有两个模块。一个是创建SpringApplication实例,还有一个是run方法。
这篇文章主要就介绍SpringApplication实例的创建,代码如下,主要包含如下7个步骤
1.将资源初始化加载器置空。
2.断言资源加载类不能为 null,否则报错
3.初始化加载资源类集合并去重
4.推断当前 WEB 应用类型,WebApplicationType
5.设置应用上下文初始化器
6.设置监听器
7.推断主应用类
其中 #1 ,#2 ,#3 不需要赘述。
#4推断当前web应用类型的流程如下
this.webApplicationType = WebApplicationType.deduceFromClasspath();
进入到 WebApplicationType.java 类的静态deduceFromClasspath 方法
static WebApplicationType deduceFromClasspath() {
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;
}
}
return WebApplicationType.SERVLET;
}
ClassUtils.isPresent是用于判断由提供的类名(类的全限定名)标识的类是否存在并可以加载,如果类或其中一个依赖关系不存在或无法加载,则返回false。
注意这里的两个宏定义如下
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
也就是如果包含
org.springframework.web.reactive.DispatcherHandler 且不包含 org.springframework.web.servlet.DispatcherServlet 的时候,那么当前应用是 reactive 模式,如果org.springframework.web.servlet.DispatcherServlet 存在且可以被加载,那么当前是 servlet 模式
关于webflux 参考 https://www.cnblogs.com/niechen/p/9303451.html
这里得到应的类型是 SERVLET 类型
#5设置应用上下文初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
#5-1. 加载应用上下文初始化类getSpringFactoriesInstances(ApplicationContextInitializer.class)
1.获取当前线程上下文类加载器
2.获取 ApplicationContextInitializer 的实例名称集合并去重,其实就是获取spring.factories中的3.配置类列表(在注解篇已经研究过)
4.根据返回的实例名称集合进行实例的创建并返回列表
5.实例列表排序
6.实例列表返回
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// 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;
}
#5-1-1 getClassLoader()得到的线程上下文类加载器的结果如下
5-1-2 SpringFactoriesLoader.loadFactoryNames() 获取 ApplicationContextInitializer 的实例名称集合并去重,其实就是获取spring.factories中的配置类列表
可以看到加载类型为ApplicationContextInitializer的类有7个。
那么这7个ApplicationContextInitializer类的定义,分别在两个spring.factories中定义
/Users/yyrj/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-autoconfigure/2.2.2.RELEASE/2e7876e237097d36bfffd5ce3416930f6d6b579c/spring-boot-autoconfigure-2.2.2.RELEASE.jar!/META-INF/spring.factories
定义了两个ApplicationContextInitializer的类。
/Users/yyrj/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot/2.2.2.RELEASE/cc636f24a5ebbfb21f1c8c30ed9c3b13512c16ec/spring-boot-2.2.2.RELEASE.jar!/META-INF/spring.factories
5-1-3 createSpringFactoriesInstances()根据返回的实例名称集合进行实例的创建、排序、返回
5-2 setInitializers()
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
/**
* Sets the {@link ApplicationContextInitializer} that will be applied to the Spring
* {@link ApplicationContext}.
* @param initializers the initializers to set
*/
public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<>(initializers);
}
#6设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
6-1这个getSpringFactoriesInstances()的流程和#5中的一样。只是加载的类型为 ApplicationListener
执行完毕后得到的监听器 11 个
这11个分布在
/Users/yyrj/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-autoconfigure/2.2.2.RELEASE/2e7876e237097d36bfffd5ce3416930f6d6b579c/spring-boot-autoconfigure-2.2.2.RELEASE.jar!/META-INF/spring.factories
中有1个
/Users/yyrj/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot/2.2.2.RELEASE/cc636f24a5ebbfb21f1c8c30ed9c3b13512c16ec/spring-boot-2.2.2.RELEASE.jar!/META-INF/spring.factories
中有10个
6-2 setListeners()
/**
* Sets the {@link ApplicationListener}s that will be applied to the SpringApplication
* and registered with the {@link ApplicationContext}.
* @param listeners the listeners to set
*/
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
this.listeners = new ArrayList<>(listeners);
}
#7推断主应用类
this.mainApplicationClass = deduceMainApplicationClass();
这里最终将this.mainApplicationClass赋值为需要加载的主类。
也就是 this.mainApplicationClass = class com.example.demo.DemoApplication
到这里SpringApplication实例创建完毕。
witch_soya
2020年01月10日