Skip to content

Latest commit

 

History

History
155 lines (120 loc) · 5.7 KB

SpringBootStart-upProcedure.md

File metadata and controls

155 lines (120 loc) · 5.7 KB

SpringBoot启动过程

一个Application被注解为 @SpringBootApplication,通过 main 方法开始、SpringApplication.run(Object source, String... args)运行。

本文是基于 SpringBoot 2.1.0.RELEASE 进行解析

启动过程概要

一、初始化资源

通过 SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) 构造方法初始化一些资源;

2、将基础参数资源添加到 LinkedHashSet<Class<?>>

3、分析Web应用的类型;

4、通过SpringFactoriesLoader#loadFactoryNames()加载工厂名称,然后使用createSpringFactoriesInstances()创建工厂的实例对象的集合;

5、设置监听器的集合;

6、通过main()方法判断并获得出所在的Application类;

二、运行Spring应用,创建并刷新一个新的 ApplicationContext

初始化完了基本资源,调用 org.springframework.boot.SpringApplication#run(String... args) 然后运行该Spring 应用,创建并刷新一个新的 ApplicationContext

1、创建并启动一个任务秒表StopWatch(此秒表注意用于在概念验证期间验证性能);

2、配置 headless属性的模式

Application初始化过程:

不同于 1.5.6 版本的使用 initialize(sources) 初始化方法进行初始化资源,2.1.0 使用构造方法进行初始化资源。

/**
 * 创建一个新的 SpringApplication 实例。此 application context 将从指定的基础资源 SpringApplication类级文件加载 beans 详情。实例可以在调用 run(String... args) 方法前定制化。
 * @param resourceLoader 使用的资源加载器
 * @param primarySources 基础 bean 资源
 * @see #run(Class, String[])
 * @see #setSources(Set)
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
    // 如果为 primarySources == null,那么直接停止运行(run方法一定要填**Application.class)
	Assert.notNull(primarySources, "PrimarySources must not be null");
    // 将 **Application.class 添加到 LinkedHashSet<Class<?>> (1.5.6是Object泛型)
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 推导web应用的类型
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 设置初始化器
	setInitializers((Collection) getSpringFactoriesInstances(
			ApplicationContextInitializer.class));
    // 设置监听器
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 推导主函数的类
	this.mainApplicationClass = deduceMainApplicationClass();
}
1、将 Application 添加到到 Set 容器

容器是 LinkedHashSet<Class<?>>

private Set<Class<?>> primarySources;
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
2、根据类路径推导Web应用
static WebApplicationType deduceFromClasspath() {
	if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
			&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
			&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
        // Spring 5.x 新特性之一就是reactive响应式编程,此处推导出响应式reactive web server
		return WebApplicationType.REACTIVE;
	}
	for (String className : SERVLET_INDICATOR_CLASSES) {
		if (!ClassUtils.isPresent(className, null)) {
            /* 
             * 如果存在Servlet或Spring ConfigurableWebApplicationContext
             * 推导出是一般的 web server
			 */return WebApplicationType.NONE;
		}
	}
    // 否则就认为是 Servlet 服务
	return WebApplicationType.SERVLET;
}
3、设置/添加初始化器(将初始化器添加到ArrayList)

设置/添加 ApplicationContextInitializer.class 为初始化器

setInitializers((Collection) getSpringFactoriesInstances(
			ApplicationContextInitializer.class));
// --------------------------------------------------
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 = Thread.currentThread().getContextClassLoader();
	// 使用名称并确保唯一性以防止重复
	Set<String> names = new LinkedHashSet<>(
			SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // 将创建后的实例放入 List
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
			classLoader, args, names);
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}
4、设置/添加监听器

设置/添加 ApplicationListener.class 为监听器(同上)

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
5、推断main方法所在的Application应用类

虚拟机栈是方法的执行模型,从栈信息查找 mian 方法所在的类

private Class<?> deduceMainApplicationClass() {
	try {
		StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
		for (StackTraceElement stackTraceElement : stackTrace) {
            // 判断栈追踪元素的方法是否等于 main 方法
			if ("main".equals(stackTraceElement.getMethodName())) {
                // 则根据此实例的类名称获取类,并返回
				return Class.forName(stackTraceElement.getClassName());
			}
		}
	}
	catch (ClassNotFoundException ex) {
		// 啥也不处理,并继续
	}
	return null;
}