springboot的启动流程主要包括以下部分:
一、SpringBootApplication启动类
启动类的常见写法
@SpringBootApplication
public class SpringmvcApplication {
public static void main(String[] args) {
SpringApplication.run(SpringmvcApplication.class, args);
}
}
需要重点关注的是@SpringBootApplication注解和SpringApplication.run(SpringmvcApplication.class, args)方法。
二、SpringApplication.run方法
1.实例化SpringApplication
SpringApplication.run(SpringmvcApplication.class, args)调用的方法;
//启动类调的run方法
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
//调的是下面的,参数是数组的run方法
return run(new Class<?>[] { primarySource }, args);
}
//和上面的方法区别在于第一个参数是一个数组
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
//实际上new一个SpringApplication实例,调的是一个实例方法run()
return new SpringApplication(primarySources).run(args);
}
判断当前项目类型
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
//断言primarySources不能为null,如果为null,抛出异常提示
Assert.notNull(primarySources, "PrimarySources must not be null");
//启动类传入的Class
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//判断当前项目类型,有三种:NONE、SERVLET、REACTIVE
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//设置ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//判断主类,初始化入口类
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;
}
设置初始化器
从类路径中META-INF/spring.factories加载对应的配置文件,读取配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value。
//设置初始化器(Initializer),最后会调用这些初始化器 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));
//设置初始化器(Initializer),最后会调用这些初始化器
setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
// 这里的入参type就是ApplicationContextInitializer.class
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// 使用Set保存names来避免重复元素
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 根据names来进行实例化
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
// 对实例进行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
// 这里的入参type就是ApplicationContextInitializer.class
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// 使用Set保存names来避免重复元素
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 根据names来进行实例化
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
// 对实例进行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
设置监听器类。 主要的方式和设置初始化类一样。
整个流程:
总结
1、构造SpringApplication对象
主要判断容器类型是否为servlet、reactive还是none
2、获取ApplicationContextInitializer对象
从META-INF/spring.factories获取容器初始化需要的初始化对象
3、获取ApplicationListener对象
从META-INF/spring.factories获取监听器的配置类
2.执行run()方法
实例化后就是执行run()方法;
主要包括以下步骤:
-
第一步:获取并启动监听器
-
第二步:根据SpringApplicationRunListeners以及参数来准备环境
-
创建Environment环境变量
- 会查询系统变量,环境变量还有启动参数
-
第三步:创建Spring容器
-
第四步:Spring容器前置处理
-
第五步:刷新容器
- 将启动类作为配置类传给run()方法,作为spring容器的配置类
-
第六步:Spring容器后置处理
-
第七步:发出结束执行的事件
-
第八步:执行Runners
-
在springboot的启动过程中会执行ApplicationRunner和CommandLineRunner类型的bean
1.获取Spring容器中的ApplicationRunner类型的Bean
2.获取Spring容器中的CommandLineRunner类型的Bean
3.执行它们的run()
-
会在springcontext创建之前就包environment环境变量准备好;
public ConfigurableApplicationContext run(String... args) {
// 计时工具
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 第一步:获取并启动监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 第二步:根据SpringApplicationRunListeners以及参数来准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
configureIgnoreBeanInfo(environment);
// 准备Banner打印器 - 就是启动Spring Boot的时候打印在console上的ASCII艺术字体
Banner printedBanner = printBanner(environment);
// 第三步:创建Spring容器
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 第四步:Spring容器前置处理
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
// 第五步:刷新容器
refreshContext(context);
// 第六步:Spring容器后置处理
afterRefresh(context, applicationArguments);
// 第七步:发出结束执行的事件
listeners.started(context);
// 第八步:执行Runners
this.callRunners(context, applicationArguments);
stopWatch.stop();
// 返回容器
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, exceptionReporters, ex);
throw new IllegalStateException(ex);
}
}
3.项目启动可选的初始化操作
- 通过ApplicationRunner和CommandLineRunner
- 通过InitializingBean注解
- 通过监听事件来处理
参考资料
- SpringBoot启动流程是怎样的?:juejin.cn/post/689534…
- SpringBoot 源码解析 (二)----- Spring Boot精髓:启动流程源码分析:www.cnblogs.com/java-chen-h…
todo
- 文章细节待补充待优化