SpringBoot启动流程
SpringBoot启动流程主要分为两大步骤:
第一步:构造一个SpringApplication的实例,完成初始化的工作。初始化的时候会做以下两件事:
(1)创建并初始化ApplicationInitializer,设置到initializers属性中 。
(2)创建并初始化ApplicationListener,设置到listeners属性中 。
第二步:SpringApplication构造完成之后调用run方法,启动SpringApplication。run方法执行的时候会做以下几件事:
(1)创建并初始化计时器StopWatch,用来记录SpringBoot的启动时间 。
(2)创建并初始化监听器SpringApplicationRunListeners,并启动监听,用于监听run方法的执行。
(3)创建并初始化ApplicationArguments,获取run方法传递的args参数。
(4)创建并初始化环境配置ConfigurableEnvironment。封装main方法的参数,写入到 Environment中,发布 ApplicationEnvironmentPreparedEvent(环境事件)。
(5)创建应用程序上下文ApplicationContext。ApplicationContext是Spring中的核心接口和容器,允许容器通过应用程序上下文环境创建、获取、管理bean。
public ConfigurableApplicationContext run(String... args) {
// 创建并初始化计时器StopWatch,用来记录SpringBoot的启动时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
// 创建并初始化监听器SpringApplicationRunListeners,并启动监听,用于监听run方法的执行
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 创建并初始化ApplicationArguments,获取run方法传递的args参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 创建并初始化环境配置ConfigurableEnvironment。封装main方法的参数,写入到 Environment中,
// 发布 ApplicationEnvironmentPreparedEvent(环境事件)。
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
// 创建应用程序上下文ApplicationContext
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
首先,run()中定义了一个StopWatch类的实例stopWatch,并在该实例上调用start()方法,用于启动计时器记录应用程序启动过程中所用的时间。
然后,创建了一个DefaultBootstrapContext类的实例bootstrapContext,用于记录Spring Boot的启动上下文信息。
接着,调用了configureHeadlessProperty()方法来配置Headless模式。
然后,获取Spring Boot的启动监听器SpringApplicationRunListeners实例,并在它上面调用starting()方法,通知所有的启动监听器:
应用程序已经开始启动了。
在try块内,首先创建了一个ApplicationArguments实例applicationArguments,用于保存应用程序启动时的相关参数。
接着,调用prepareEnvironment()方法创建并准备ConfigurableEnvironment实例environment,包括加载所有的配置文件、设置激活的profile、
解析命令行参数等,并配置忽略bean的信息。
然后,调用printBanner()方法打印Spring Boot logo,同时将返回的Banner实例printedBanner保存。
紧接着,调用createApplicationContext()方法创建ApplicationContext实例context,并将applicationStartup配置到context实例中。
然后,调用prepareContext()方法,来准备上下文,包括配置beans、设置profiles、注册监听器等,并且将printedBanner通过
context的属性banner进行记录。在prepareContext()方法中还会回调SpringApplicationRunListeners实例的方法:contextPrepared()。
接下来,调用refreshContext()方法启动容器(这里涉及到Spring的容器启动顺序、扫描bean的逻辑等),达到Spring Bean的依赖注入功能。
然后,在Context刷新完成后,调用afterRefresh()方法,将相关的applicationContext和applicationArguments传入,对Spring Boot进行
后续的处理。
在stopWatch上调用stop()方法,计算出应用程序从启动到加载完毕所需的总时间。如果打开了日志输出,则调用StartupInfoLogger实例的方法
记录应用程序启动的日志。
接着,会调用SpringApplicationRunListeners实例的方法:started() 和callRunners()。
最后,在try块外,会再次回调SpringApplicationRunListeners实例的方法:running()。如果在try块中执行过程中,出现了异常,
则通过handleRunFailure()方法进行异常处理。整个方法最终会返回ApplicationContext实例context。
Spring Boot 的启动过程大致如下:
1. 创建启动计时器和Spring Boot启动上下文
2. 配置Headless模式
3. 创建和通知Spring Boot的启动监听器
4. 创建和准备应用程序运行参数、环境、解析命令行等
5. 打印Spring Boot Logo,并创建Spring IoC容器、注册监听器、配置Beans、设置Profiles等
6. 启动IoC容器,完成Bean的扫描、注入等工作
7. 容器加载完毕后,进行后续的处理操作
8. 停止计时器并记录应用程序启动的日志
9. 调用监听器已完成启动的方法和处理方法
10. 返回ApplicationContext实例。