探索 SpringBoot (二) 启动流程详解(上)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35704236/article/details/84193671

探索 SpringBoot (二) 启动流程详解

1 缘起

从 SpringApplication.run(xxx.class, args); 开始,看看 SpringBoot 为我们做了什么

2 环境配置

  • 1 本文源码基于 spring-boot-2.1.0.RELEASE
  • 2 本文将从两个阶段来讲解 SpringBoot 的具体启动流程,分别是 准备阶段 和 运行阶段
  • 3 因为内容比较多 打算分成两篇,上篇将 准备阶段 下篇将运行阶段

3 SpringApplication 准备阶段

new SpringApplication(primarySources)

  • 1 调用 run 方法 传入配置主类,和运行时候参数
public static ConfigurableApplicationContext run(Class<?> primarySource,
		String... args) {
	return run(new Class<?>[] { primarySource }, args);
}
  • 2 进入准备阶段并且运行,我们接着往下看看 SpringApplication 的构造方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
		String[] args) {
	return new SpringApplication(primarySources).run(args);
}
  • 3 这里主要做了两件事情
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 = WebApplicationType.deduceFromClasspath();
	setInitializers((Collection) getSpringFactoriesInstances(
			ApplicationContextInitializer.class));
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}
3.1 推断
    // 推断 web app 类型
    WebApplicationType.deduceFromClasspath();
    
    // 推断运行主类
    this.mainApplicationClass = deduceMainApplicationClass();
    
3.2 设置  

    // 根据 Spring 工厂方法加载 Initializers
    setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
				
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

3.1 推断 web app 类型

WebApplicationType.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;
}
- 这里就只做了 3 件事情
1  判断 常量 WEBFLUX_INDICATOR_CLASS 所表示的类 是否存在并且可以加载 如果 true 则返回 WebApplicationType.REACTIVE

2 判断 常量 SERVLET_INDICATOR_CLASSES 所表示的类 是否存在并且可以加载
如果有一个 false 返回 WebApplicationType.NONE

3 如果上面条件都没满足 返回 WebApplicationType.SERVLET

3.2 推断 运行主类

this.mainApplicationClass = deduceMainApplicationClass();

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;
}
  • 这里就是获取当前运行时候的堆栈信息,找到 “main” 方法的类并且返回

3.3 根据 (order )采用 SpringFactory 的方式初始化 ApplicationContextInitializer 的实现类,并且排序

setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));

...

public void setInitializers(
			Collection<? extends ApplicationContextInitializer<?>> initializers) {
	this.initializers = new ArrayList<>();
	this.initializers.addAll(initializers);
}
  • 这个方法就是把初始化得到的实现类设置成成员变量,我们关键看下面这个方法
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;
}
 这里主要做了 2 件事
 
 1 从 classpath 下面获取 spring.facoty 中, ApplicationContextInitializer 获取 该接口实现类的全类名
 2 根据获取的 全类名 初始化 实现类 并且排序
  • 好吧 结合代码再看看
Set<String> names = new LinkedHashSet<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
				
				
...


public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
	String factoryClassName = factoryClass.getName();
	return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
	MultiValueMap<String, String> result = cache.get(classLoader);
	if (result != null) {
		return result;
	}

	try {
		Enumeration<URL> urls = (classLoader != null ?
				classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
				ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
		result = new LinkedMultiValueMap<>();
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			UrlResource resource = new UrlResource(url);
			Properties properties = PropertiesLoaderUtils.loadProperties(resource);
			for (Map.Entry<?, ?> entry : properties.entrySet()) {
				String factoryClassName = ((String) entry.getKey()).trim();
				for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
					result.add(factoryClassName, factoryName.trim());
				}
			}
		}
		cache.put(classLoader, result);
		return result;
	}
	catch (IOException ex) {
		throw new IllegalArgumentException("Unable to load factories from location [" +
				FACTORIES_RESOURCE_LOCATION + "]", ex);
	}
}
  • 这里的主要作用就是 加载 classpath 下面所有叫 META-INF/spring.factories 的文件,并且解析里面的 key 和 value 放入 map 中返回

  • 我们再来看看第二点

List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
				
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
			Set<String> names) {
	List<T> instances = new ArrayList<>(names.size());
	for (String name : names) {
		try {
			Class<?> instanceClass = ClassUtils.forName(name, classLoader);
			Assert.isAssignable(type, instanceClass);
			Constructor<?> constructor = instanceClass
					.getDeclaredConstructor(parameterTypes);
			T instance = (T) BeanUtils.instantiateClass(constructor, args);
			instances.add(instance);
		}
		catch (Throwable ex) {
			throw new IllegalArgumentException(
					"Cannot instantiate " + type + " : " + name, ex);
		}
	}
	return instances;
}
  • 这里无非就是通过反射 初始化 上面的实现类

3.4 根据 (order )采用 SpringFactory 的方式初始化 ApplicationListener 的实现类,并且排序

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  • 这个的实现就和上面类似了 参照上面吧。

到此为止 SpringApplicaiton 的准备阶段就结束啦,我们一起看看 运行阶段做了啥吧。


猜你喜欢

转载自blog.csdn.net/qq_35704236/article/details/84193671
今日推荐