SpringApplication 类 run 方法源码
public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();this.configureHeadlessProperty();/**'1:加载所有的 SpringApplicationRunListeners'*/SpringApplicationRunListeners listeners = this.getRunListeners(args);listeners.starting();Collection exceptionReporters;try {/**'2:创建并配置当前应用将要使用的 Environment'*/ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);this.configureIgnoreBeanInfo(environment);/**'3:SpringBoot 的 banner图 output中的图片'*/Banner printedBanner = this.printBanner(environment);/**'4:根据是否是web项目,来创建不同的ApplicationContext容器'*/context = this.createApplicationContext();/**' 新增 '*/exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);/**'6:初始化ApplicationContext'*/this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);/**'7:就是插手容器的启动'*/this.refreshContext(context);/**'8:查找当前context中是否注册有CommandLineRunner和ApplicationRunner,如果有则遍历执行它们。'*/this.afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);}/**'9:执行所有SpringApplicationRunListener的started()方法。'*/listeners.started(context);this.callRunners(context, applicationArguments);} catch (Throwable var10) {this.handleRunFailure(context, var10, exceptionReporters, listeners);throw new IllegalStateException(var10);}
1:通过SpringFactoriesLoader查找并加载所有的 SpringApplicationRunListeners。
通过调用starting()方法通知所有的SpringApplicationRunListeners:应用开始启动了。SpringApplicationRunListeners其本质上就是一个事件发布者,它在SpringBoot应用启动的不同时间点发布不同应用事件类型(ApplicationEvent),如果有哪些事件监听者(ApplicationListener)对这些事件感兴趣,则可以接收并且处理。还记得初始化流程中,SpringApplication加载了一系列ApplicationListener吗?这个启动流程中没有发现有发布事件的代码,其实都已经在SpringApplicationRunListeners这儿实现了。
2: 创建并配置当前应用将要使用的 Environment,Environment用于描述应用程序当前的运行环境,其抽象了两个方面的内容:配置文件(profile)和属性(properties),开发经验丰富的同学对这两个东西一定不会陌生:不同的环境(eg:生产环境、预发布环境)可以使用不同的配置文件,而属性则可以从配置文件、环境变量、命令行参数等来源获取。因此,当Environment准备好后,在整个应用的任何时候,都可以从Environment中获取资源。
- 判断Environment是否存在,不存在就创建(如果是web项目就创建 StandardServletEnvironment,否则创建
- StandardEnvironment) 配置Environment:配置profile以及properties
调用SpringApplicationRunListener的 - environmentPrepared()方法,通知事件监听者:应用的Environment已经准备好
3:SpringBoot 的 banner图 output中的图片
4:根据是否是web项目,来创建不同的ApplicationContext容器
6:初始化ApplicationContext,主要完成以下工作:
-
将准备好的Environment设置给ApplicationContext
-
遍历调用所有的ApplicationContextInitializer的
initialize()方法来对已经创建好的ApplicationContext进行进一步的处理 -
调用SpringApplicationRunListener的
contextPrepared()方法,通知所有的监听者:ApplicationContext已经准备完毕 -
将所有的bean加载到容器中
-
调用SpringApplicationRunListener的
contextLoaded()方法,通知所有的监听者:ApplicationContext已经装载完毕
7:调用ApplicationContext的 refresh()方法,完成IoC容器可用的最后一道工序。就是插手容器的启动
8:查找当前context中是否注册有CommandLineRunner和ApplicationRunner,如果有则遍历执行它们。
9:执行所有SpringApplicationRunListener的started()方法。