1. initialize 方法
SpringApplication
的构造函数只调用了 initialize
方法:
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
// 把应用指定的配置类加入配置扫描的启动来源
this.sources.addAll(Arrays.asList(sources));
}
// 判断应用是否是 web 应用,主要用于决定采用哪种具体的上下文实现
this.webEnvironment = deduceWebEnvironment();
// 利用定制的 SPI 实现 SpringFactoriesLoader 加载 ApplicationContextInitializer 的所有实现并设置到 initializers 属性
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 利用定制的 SPI 实现 SpringFactoriesLoader 加载 ApplicationListener 的所有实现并设置到 listeners 属性
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 找出启动类:线程栈上 main 方法所处的类
this.mainApplicationClass = deduceMainApplicationClass();
}
该方法的逻辑主要如下:
- 把启动类加入 sources 属性。
- 判断是否是 web 应用并设置到 webEnvironment 属性。
- 加载所有的 ApplicationContextInitializer 并设置到 initializers 属性。
- 加载所有的 ApplicationListener 并设置到 listeners 属性。
- 找出 main 类设置到 mainApplicationClass。
2. run 方法
public ConfigurableApplicationContext run(String... args) {
// StopWatch 主要用来统计应用的启动时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
// 配置 AWT 的 headless 属性
configureHeadlessProperty();
// 初始化事件广播器,用于广播事件
SpringApplicationRunListeners listeners = getRunListeners(args);
// 触发 SpringApplicationRunListener.starting 方法
// 向 ApplicationListener 广播 ApplicationStartedEvent 事件
listeners.starting();
try {
// 封装命令行参数,后面会注册到上下文里
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 创建并准备 Environment
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 打印 Banner
Banner printedBanner = printBanner(environment);
// 创建 ApplicationContext
context = createApplicationContext();
// 创建失败分析器
analyzers = new FailureAnalyzers(context);
//
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新上下文,加载所有的Bean定义并实例化非延迟加载的单例Bean
refreshContext(context);
// 获取所有的 ApplicationRunner 和 CommandLineRunner 并执行其回调
afterRefresh(context, applicationArguments);
// 广播 ApplicationReadyEvent或ApplicationFailedEvent事件
listeners.finished(context, null);
// 终止计时
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
return context;
} catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
run 方法的核心逻辑:
- 创建 StopWatch 用于记录启动耗时;
- 创建并准备 Enviroment。加载所有的配置文件和处理 Profile 。
- 创建并准备 ApplicationContext ,把
ConfigurationClassPostProcessor
注册到上下文底层的BeanFacotry
。 - 刷新 ApplicationContext。
- 获取所有的
ApplicationRunner
和CommandLineRunner
并执行其回调。 - 广播 ApplicationReadyEvent或ApplicationFailedEvent事件。
这个流程非常简单,不涉及具体的配置文件解析、加载,bean 定义扫描、解析、加载、实例化 bean 等。就是 SpringBoot 特有的流程,比如打印 Banner、回调 Runner 方法,中间适时广播事件。
欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。