Springboot启动流程分析-2——创建SpringApplication实例

在上一篇中,提到主要有两个模块。一个是创建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日

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值