Spring Boot 深度解析:从 0 到 1 探索启动之谜
引言
在日常开发中,我们经常使用
Spring Boot来快速构建 Web 应用,但你是否深入思考过它的启动流程是如何工作的?当你在main方法中调用SpringApplication.run()时,Spring Boot 究竟经历了哪些关键步骤,最终成功启动了应用?本篇文章将深入 Spring Boot 源码,剖析其启动流程,帮助你理解它的内部原理,让你在排查问题、优化启动速度时更加得心应手。
1. 启动入口
Spring Boot 应用通常以 SpringApplication.run() 作为入口:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
该方法会初始化 SpringApplication 并调用 run() 方法启动 Spring Boot 应用。
2. SpringApplication.run() 启动流程
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
listeners.started(context, timeTakenToStartup);
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;
}
Spring Boot 的启动过程可以拆解为以下阶段:
1. 创建 SpringApplication 对象
public SpringApplication(Class<?>... primarySources) {
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
- 通过
SpringFactoriesLoader加载ApplicationContextInitializer和ApplicationListener - 确定
WebApplicationType
2. 监听器通知 starting 事件
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this);
Spring Boot 触发 starting 事件,通知监听器应用正在启动。
3. 准备 Environment (环境变量)
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
- 加载
application.properties或application.yml - 通知监听器
environmentPrepared事件
4. 打印 Spring Boot Banner
Banner printedBanner = printBanner(environment);
- 可通过
spring.banner.location自定义 Banner。
5. 创建 ApplicationContext
context = createApplicationContext();
- Web 应用创建
AnnotationConfigServletWebServerApplicationContext - 普通应用创建
AnnotationConfigApplicationContext
6. 准备 Spring 容器
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
- 调用
ApplicationContextInitializer - 通知监听器
contextPrepared
7. 加载 Bean 定义
load(context, sources.toArray(new Object[0]));
- 通过
AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner扫描 Bean
8. 刷新 ApplicationContext
refreshContext(context);
最终调用 AbstractApplicationContext.refresh(),执行 BeanFactory 初始化流程。
9. 触发 started 事件
listeners.started(context, timeTakenToStartup);
并执行 ApplicationRunner 和 CommandLineRunner:
callRunners(context, applicationArguments);
10. 通知 running 事件
listeners.running(context);
至此,Spring Boot 启动完成!
总结:Spring Boot 启动核心流程
- 创建
SpringApplication,加载监听器、环境类型。 - 触发
starting事件,通知监听器应用正在启动。 - 准备
Environment,解析application.properties配置文件。 - 打印 Banner。
- 创建
ApplicationContext并注册环境。 - 调用
ApplicationContextInitializer进行上下文初始化。 - 加载 Bean,注册
BeanDefinition。 - 刷新
ApplicationContext,完成 Bean 实例化、依赖注入。 - 触发
started事件,执行ApplicationRunner和CommandLineRunner。 - 通知
running事件,Spring Boot 启动完成。
整个启动流程以 SpringApplication.run() 作为起点,结合监听器、环境、应用上下文、BeanFactory 等组件,实现了 Spring Boot 的自动化启动。
版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
LibSept24_!
喜欢就支持一下吧
打赏
微信
支付宝
微信
支付宝