前言
SpringBoot应用的启动过程是一个复杂但设计精巧的流程,了解这个过程对于深入理解SpringBoot工作原理至关重要。本文将详细解析SpringBoot应用的完整[启动流程]。
一、SpringApplication初始化阶段
1. 创建SpringApplication实例
SpringBoot应用启动的第一步是创建SpringApplication实例:
typescript
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
AI写代码java
运行
123456
在SpringApplication的构造函数中,会进行以下关键操作:
scss
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 保存主配置类信息
this.resourceLoader = resourceLoader;
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 判断应用类型:SERVLET、REACTIVE 或 NONE
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 获取并初始化BootstrapRegistryInitializer
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// 获取ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 获取ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断主应用类
this.mainApplicationClass = deduceMainApplicationClass();
}
AI写代码java
运行
12345678910111213141516171819202122
2. 加载SPI扩展组件
SpringBoot通过spring.factories机制加载各种扩展组件:
- BootstrapRegistryInitializer: 引导注册表初始化器
- ApplicationContextInitializer: 应用上下文初始化器
- ApplicationListener: 应用事件监听器
二、应用运行阶段
1. 启动计时与引导上下文
ini
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 创建引导上下文
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
// 获取运行监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
}
AI写代码java
运行
1234567891011121314
2. 环境准备
环境准备阶段负责配置应用运行所需的[环境变量]和配置属性:
scss
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 创建适当类型的环境对象
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置环境:加载配置文件、命令行参数等
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 发布EnvironmentPrepared事件
listeners.environmentPrepared(bootstrapContext, environment);
// 将环境绑定到SpringApplication
bindToSpringApplication(environment);
return environment;
}
AI写代码java
运行
123456789101112131415161718
环境配置过程:
- 返回或者创建基础设施信息对象:
StandardServletEnvironment- 配置环境信息对象
- 读取所有的配置源的配置属性值
- 绑定环境信息
- 监听器调用
listener.environmentPrepared(),通知所有监听器当前环境准备完成
3. 创建IOC容器
根据应用类型创建相应的ApplicationContext:
kotlin
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
AI写代码java
运行
123
根据项目类型创建容器:
- 对于Servlet应用,会创建
AnnotationConfigServletWebServerApplicationContext- 对于Reactive应用,会创建
AnnotationConfigReactiveWebServerApplicationContext- 对于普通应用,会创建
AnnotationConfigApplicationContext
4. 准备IOC容器
scss
private void prepareContext(DefaultBootstrapContext bootstrapContext,
ConfigurableApplicationContext context,
ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments,
Banner printedBanner) {
// 设置环境
context.setEnvironment(environment);
// 应用上下文后置处理
postProcessApplicationContext(context);
// 应用初始化器
applyInitializers(context);
// 发布ApplicationContextInitialized事件
listeners.contextPrepared(context);
// 注册Bean定义
load(context, sources.toArray(new Object[0]));
// 发布ApplicationContextLoaded事件
listeners.contextLoaded(context);
}
AI写代码java
运行
12345678910111213141516171819202122232425
准备ApplicationContext IOC容器的基本信息 prepareContext() :
- 保存环境信息
- IOC容器的后置处理流程
- 应用初始化器:
applyInitializers- 遍历所有的
ApplicationContextInitializer,调用initialize,来对IOC容器进行初始化扩展功能- 遍历所有的监听器调用
contextPrepared,通知所有的监听器contextPrepare- 所有的监听器调用
contextLoaded,通知所有的监听器contextLoaded
5. 刷新IOC容器
这是SpringBoot启动过程中最核心的步骤:
scss
private void refreshContext(ConfigurableApplicationContext context) {
// 注册关闭钩子
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
// 执行刷新操作
refresh(context);
}
AI写代码java
运行
123456789
实际的刷新操作委托给Spring Framework的refresh()方法:
typescript
protected void refresh(ApplicationContext applicationContext) {
applicationContext.refresh();
}
AI写代码java
运行
123
在refresh()方法中会完成:
- BeanFactory的创建和配置
- Bean的后置处理器注册
- 消息源、事件广播器等基础组件的初始化
- Web服务器的创建和启动
- 单例Bean的实例化
刷新IOC容器,refreshContext:
- 创建容器中的所有组件(Spring注解)
- 启动内嵌的Web服务器(如Tomcat)
- 完成所有Bean的创建和依赖注入
6. 容器刷新后处理
typescript
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
// 调用ApplicationRunner和CommandLineRunner
}
AI写代码java
运行
1234
7. 调用Runners
scss
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
// 获取容器中的ApplicationRunner
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
// 获取容器中的CommandLineRunner
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// 合并所有runner并且按照@Order进行排序
AnnotationAwareOrderComparator.sort(runners);
// 遍历所有的runner,调用run方法
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
AI写代码java
运行
12345678910111213141516171819202122
调用所有runners:
- 获取容器中的
ApplicationRunner- 获取容器中的
CommandLineRunner- 合并所有runner并且按照Order进行排序
- 遍历所有的runner,调用run方法
8. 启动完成事件发布
lua
// 所有监听器调用listeners.started(context),通知所有的监听器started
listeners.started(context);
// 调用所有监听器的running方法listeners.running(context),通知所有的监听器running
listeners.running(context);
AI写代码java
运行
12345
9. 异常处理
在整个启动过程中,如果出现异常,会进行相应的处理:
php
try {
// 启动流程...
} catch (Throwable ex) {
// 调用Listener的failed方法,通知所有的监听器启动失败
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
AI写代码java
运行
1234567
异常处理机制:
- 如果以上有异常,调用
Listener的failed- 调用所有监听器的running方法,如果running有问题,继续通知failed
三、关键组件详解
1. 事件监听机制
SpringBoot的启动过程通过事件监听机制实现了高度的扩展性:
- ApplicationStartingEvent: 应用启动开始时发布
- ApplicationEnvironmentPreparedEvent: 环境准备完成后发布
- ApplicationContextInitializedEvent: 应用上下文初始化后发布
- ApplicationPreparedEvent: Bean定义加载完成后发布
- ApplicationStartedEvent: 应用启动完成后发布
- ApplicationReadyEvent: 应用准备就绪后发布
- ApplicationFailedEvent: 启动失败时发布
2. Runner接口
ApplicationRunner和CommandLineRunner提供了在应用启动后执行特定代码的机制:
java
@Component
@Order(1)
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
// 应用启动后执行的逻辑
System.out.println("ApplicationRunner执行完成");
}
}
@Component
@Order(2)
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
// 命令行参数处理逻辑
System.out.println("CommandLineRunner执行完成");
}
}
AI写代码java
运行
123456789101112131415161718192021
总结
SpringBoot的启动过程是一个精心设计的流程,通过模块化的设计和事件驱动机制,实现了高度的可扩展性和灵活性。理解这个启动过程对于深入掌握SpringBoot框架、进行自定义扩展和故障排查都具有重要意义。
整个启动过程从创建SpringApplication实例开始,经过环境准备、容器创建、Bean加载、后置处理等多个阶段,最终完成应用的启动并对外提供服务。每个阶段都提供了相应的扩展点,允许开发者在适当的时机介入并添加自定义逻辑。