URL
https://mp.weixin.qq.com/s/uP4seo__qYMJMzmbWyUUnA?tdsourcetag=s_pctim_aiomsg
SpringApplication.run
- 总共做了两件事情,如下源码
- 穿件SpringApplication对象
- 利用创建好的对象调用run方法
// SpringApplication.run(Application.class, args);进入 --- 1
public static ConfigurableApplicationContext run(Object source, String... args) {
return run(new Object[] { source }, args);
}
//以上run 方法进去
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
- 此处开始分成两个部分,一部分:SpringApplication(sources)进行SpringApplication的初始化工作,包括各种配置的初始化,listener初始化等 二部分:run(args)执行run方法启动
//初始化开始
public SpringApplication(Object... sources) {
initialize(sources);
}
//initialize 方法
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
// ------1
this.sources.addAll(Arrays.asList(sources));
}
// ----------2
this.webEnvironment = deduceWebEnvironment();
//--------3
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//-----------4
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//----------5
this.mainApplicationClass = deduceMainApplicationClass();
}
//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;
}
- 在初始化步骤中
- 步骤1 保存主配置信息
- 步骤2 判断当前是否是web应用
- 步骤3中可以看到方法getSpringFactoriesInstances作用在于通过到路径META_INF/spring.factories配置中所有ApplicationContextinitializer配置信息的list,接着通过initializers 将配置信息保存
- 步骤4 中同步骤3 一致,只不过这次获取的配置类型不同,连调用的方法都是一样的,这次获取的是ApplicationListener类型的配置,之后保存
- 步骤5 中的deduceMainApplicationClass 方法在寻址一个包含main方法的配置类,如上部分代码,也就是我们自己写的启动类
- 第二部分则是运行对应的run方法:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
//-----------1
SpringApplicationRunListeners listeners = getRunListeners(args);
//-----------2
listeners.starting();
try {
//----------3
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// ----------4
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//--------5
Banner printedBanner = printBanner(environment);
//----------6
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
//---7
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//---8
refreshContext(context);
// -----------9
afterRefresh(context, applicationArguments);
//--------10
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// --------11
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
// 4步骤中流程:
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);
if (!this.webEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
return environment;
}
- run方法解析:
- 此处先调用getRunListeners方法,同之前一样,是获取META_INF/Spring.factories文件中的配置信息,配置信息类型是:SpringApplicationRunListeners
- 在得到对应的配置信息后,调用gstarting方法,改方法会去循环调用刚才获取到的所有配置,并且触发SpringApplicationRunListener中的starting事件,并且是异步的形式触发
- 接着封装我们的命令行参数,也就是我们main方法中传入的args参数封装成对应的ApplicationArguments,
- 此处步骤会先准备对应环境,主要是我们在配置的配置信息的驾照,在完成环境准备之后在listeners.environmentPrepared(environment); 方法中会回调SpringApplicationRunListener中的environmentPrepared 事件,也是同样的异步的方式触发
- 这个步骤pringBanner,启动时候banner的打印,可以自定义自步骤中的图形
- createApplicationContext方法会更具我们之前环境判断信来是web环境还是其他决定创建web还是普通的IOC容器
- 此步骤中有多个功能
- 将environment上下文环境信息保存早ioc容器中
- 执行applyInitializers 方法,改方法会遍历之前保存的ApplicationContextInitializer的initialize()事件
- 在contextPerpared中遍历SpringApplicationRunListener中的ContextPrepared()事件
- 最后在contextLoaded方法中回调SpringApplicationRunListener中的ContextLoaded()事件
- refreshContext顾名思义,刷新容器,进行组件的扫描创建,加载等
- afterRefresh从IOC容器中获取所有ApplicationRunner和CommandLineRunner遍历所有runner并且调用callRunner方法回调用,先调用ApplicationRunner,在调用CommandLineRunner
- finished方法中遍历SpringApplicationRunListener中的finished()事件
- 最后返回context ioc容器
总结
- SpringApplication.run一共做了两件事,一件是创建SpringApplication对象,在该对象初始化时,找到配置的事件监听器,并保存起来.第二件事就是运行run方法,此时会将刚才保存的事件监听器根据当前时机触发不同的事件,比如容器初始化,容器创建完成等.同时也会刷新IoC容器,进行组件的扫描、创建、加载等工作.