-
前言
前一篇文章【 SpringBoot 】- [SpringApplication] -- 初始化 ,已经把 SpringApplication 创建完成,接下来本文将介绍启动过程:即 run() 方法的流程。
/**
* SpringApplication.java
*/
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
// 撸起 run()
return (new SpringApplication(primarySources)).run(args);
}
-
热身
老规矩,先安静下来,跟着下图默默的认一下路.......
-
开车 -> SpringApplication.run()
public ConfigurableApplicationContext run(String... args) {
// 1⃣️ 创建 StopWatch(秒表) 对象,主要用于统计启动时长
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
// 2⃣️ 配置 headlessProperty(标题属性)
this.configureHeadlessProperty();
// 3⃣️ 获取所有的运行监听器 SpringApplicationRunListeners,并启动
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
// 4⃣️ 创建应用参数对象 ApplicationArguments
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 5⃣️ 传入监听器+应用参数,配置运行环境:执行完成后,所有的 environment 的属性都会加载进来,包括 application.properties 和外部的属性配置。
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
// 6⃣️ 打印 banner(横幅)
Banner printedBanner = this.printBanner(environment);
// 7⃣️ 创建应用上下文(spring容器)
context = this.createApplicationContext();
// 8⃣️ 获取 SpringBootExceptionReporter.class 下的异常报告器集合 exceptionReporters
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
// 9⃣️ 准备 spring 上下文:主要是调用所有初始化类的 initialize 方法
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// ? 刷新 spring 上下文,即初始化spring容器
this.refreshContext(context);
// 1⃣️1⃣️ 后置处理 spring 上下文
this.afterRefresh(context, applicationArguments);
// 1⃣️2⃣️ 停止秒表,统计启动时长
stopWatch.stop();
// 1⃣️3⃣️ 打印 秒表banner 统计的容器启动时长
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
// 1⃣️4⃣️ 通知所有的监听器,容器启动完成
listeners.started(context);
// 1⃣️5⃣️ 呼叫所有的 runners 让他们奔跑起来 --> 调用所有 runners 的 run()方法
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
// 1⃣️6⃣️ 运行所有的 listener,发布监听事件
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
-
第3步 -> getRunListeners()
/**
* SpringApplication.java
*/
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
· 如约的出现了 getSpringFactoriesInstances() 惊不惊喜,意不意外!不再过多赘述:
「1」传入参数 type=SpringApplicationRunListener.class,「2」获取文件 META-INF/spring.factories 中以 SpringApplicationRunListener 为key的所有 classNames,「3」并利用反射实例化所有的listener,返回 listeners集合 ,「4」把 listeners 传入构造方法创建 SpringApplicationRunListeners 对象。
「spring.factories」 文件内容如下:只有一个事件发布监听器
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
debug 如下
pass:因为在此之前(上一篇文章)已经初始化了 SpringApplication,即已经通过 getSpringFactoriesInstances() 加载过了spring.factories文件,所以 getSpringFactoriesInstances --> loadFactoryNames --> loadSpringFactories 缓存已经存在所有的 classNames,直接返回即可,然后根据 type=SpringApplicationRunListener.class 挑选出 names。
· end:第3步的结果如下
-
第7步 -> createApplicationContext()
/**
* SpringApplication.java
*/
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
// 根据不同的 webApplicationType 获取对应的容器class 即 ApplicationContext.class
if (contextClass == null) {
try {
switch(this.webApplicationType) {
case SERVLET:
contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
break;
case REACTIVE:
contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
break;
default:
contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
}
} catch (ClassNotFoundException var3) {
throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
}
}
// 创建 ApplicationContext
return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}
这里的demo创建的是默认的注解式配置容器 --> AnnotationConfigApplicationContext
持续更新.......