Spring Boot启动流程及源码实现深度解析

news/2025/3/19 17:45:37/

Spring Boot启动流程及源码实现深度解析

一、启动流程概述

Spring Boot的启动流程围绕SpringApplication类展开,核心流程可分为以下几个阶段:

  1. 初始化阶段:推断应用类型,加载ApplicationContextInitializerApplicationListener
  2. 环境准备:加载配置文件和命令行参数
  3. 上下文创建:实例化ApplicationContext
  4. 上下文刷新:执行refresh()方法完成Bean加载
  5. 后置处理:执行CommandLineRunnerApplicationRunner

二、源码解析

1. 入口类

java">@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}

2. SpringApplication初始化

java">// SpringApplication.java
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {return new SpringApplication(primarySource).run(args);
}public SpringApplication(Class<?>... primarySources) {this(null, primarySources);
}private SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 推断应用类型setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 加载InitializerssetListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 加载Listenersthis.mainApplicationClass = deduceMainApplicationClass();
}

关键步骤解析

  • deduceFromClasspath()通过类路径判断应用类型(Servlet/Reactive/None)
  • META-INF/spring.factories加载初始化器和监听器

3. run()方法核心流程

java">public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment);Banner printedBanner = printBanner(environment);// 创建应用上下文context = createApplicationContext();context.setEnvironment(environment);// 准备上下文prepareContext(context, environment, listeners, applicationArguments, printedBanner);// 刷新上下文(核心)refreshContext(context);// 后置处理afterRefresh(context, applicationArguments);stopWatch.stop();// 发布启动完成事件listeners.started(context);callRunners(context, applicationArguments);} catch (Throwable ex) {handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}listeners.running(context);return context;
}

三、关键阶段详解

1. 环境准备(prepareEnvironment)

java">private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {ConfigurableEnvironment environment = getOrCreateEnvironment();configureEnvironment(environment, applicationArguments.getSourceArgs());ConfigurationPropertySources.attach(environment);listeners.environmentPrepared(environment); // 发布环境准备事件bindToSpringApplication(environment);return environment;
}
  • 加载application.properties/yml文件
  • 处理命令行参数--开头的参数
  • 触发ApplicationEnvironmentPreparedEvent事件

2. 上下文创建(createApplicationContext)

根据应用类型创建不同的上下文:

java">protected ConfigurableApplicationContext createApplicationContext() {return this.applicationContextFactory.create(this.webApplicationType);
}// 默认实现
ApplicationContextFactory DEFAULT = (webApplicationType) -> {try {switch (webApplicationType) {case SERVLET:return new AnnotationConfigServletWebServerApplicationContext();case REACTIVE:return new AnnotationConfigReactiveWebServerApplicationContext();default:return new AnnotationConfigApplicationContext();}} catch (Exception ex) {throw new IllegalStateException(...);}
};

3. 上下文刷新(refreshContext)

java">private void refreshContext(ConfigurableApplicationContext context) {refresh(context);if (this.registerShutdownHook) {try {context.registerShutdownHook();} catch (AccessControlException ex) {// Not allowed in some environments.}}
}protected void refresh(ApplicationContext applicationContext) {((AbstractApplicationContext) applicationContext).refresh();
}

最终调用AbstractApplicationContext.refresh(),这是Spring容器的核心方法:

java">public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {prepareRefresh();ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();prepareBeanFactory(beanFactory);// ... [省略其他步骤]finishRefresh(); // 触发ContextRefreshedEvent}
}

四、关键扩展点

1. ApplicationContextInitializer

java">public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {void initialize(C applicationContext);
}
  • 执行时机:上下文准备阶段(prepareContext)
  • 配置方式:通过spring.factoriesSpringApplication.addInitializers()

2. ApplicationRunner/CommandLineRunner

java">@Component
public class DemoRunner implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) {// 应用启动后执行}
}
  • 执行顺序:通过@Order注解控制
  • 执行时机:上下文刷新完成后

五、总结

Spring Boot的启动流程通过智能的自动配置和扩展机制,显著简化了Spring应用的初始化过程。理解其核心流程和关键扩展点,可以帮助开发者:

  1. 深入排查启动过程中的问题
  2. 实现自定义的初始化逻辑
  3. 优化应用启动性能
  4. 扩展框架的核心功能

建议结合源码调试工具,通过断点跟踪SpringApplication.run()的执行过程,可以更直观地理解各阶段的实现细节。


流程图文字描述

main()
└─▶ SpringApplication.run()├─▶ 初始化应用类型和扩展组件├─▶ 准备环境(加载配置)├─▶ 创建ApplicationContext├─▶ 准备上下文(Bean定义加载)├─▶ 刷新上下文(Bean初始化)├─▶ 执行Runner接口└─▶ 完成启动

通过以上分析,读者可以系统地掌握Spring Boot的启动机制及其实现原理。实际开发中可结合具体需求,合理使用扩展点进行定制化开发。


http://www.ppmy.cn/news/1580378.html

相关文章

C++模版(进阶)

文章目录 一、非类型模版参数二、模版的特化2.1 概念2.2 函数模版特化2.2.1 函数模版特化为指针类型注意事项 2.3 类模版特化2.3.1 全特化2.3.2 偏特化(半特化)2.3.3 类模板特化应用示例 三、模版分离编译3.1 什么是分离编译&#xff1f;3.2 模版的分离编译3.3 解决方法! 四、模…

射频前端模块(FEM)的基本原理与架构:从组成到WiFi路由器的应用

射频前端模块(FEM)的基本原理与架构:从组成到WiFi路由器的应用 一、FEM是什么? 射频前端模块(Front-End Module, FEM)是无线通信系统中负责处理射频信号的核心组件。它将多个关键电路集成在一个模块中,包括功率放大器(PA)、低噪声放大器(LNA)、射频开关(Switch)、…

深度学习处理时间序列(2)

在数据中寻找周期性 在多个时间尺度上的周期性&#xff0c;是时间序列数据非常重要且常见的属性。无论是天气、商场停车位使用率、网站流量、杂货店销售额&#xff0c;还是健身追踪器记录的步数&#xff0c;你都会看到每日周期性和年度周期性&#xff08;人类生成的数据通常还…

windows协议不再续签,华为再无windows可用,将于四月发布鸿蒙PC

大家好&#xff0c;我是国货系创始人张云泽&#xff0c;最近不少小伙伴在后台问&#xff1a;“听说Windows协议要到期了&#xff1f;我的电脑会不会变砖&#xff1f;”还有人说&#xff1a;“华为笔记本以后用不了Windows了&#xff1f;鸿蒙系统能用吗&#xff1f;”今天咱们就…

机器学习——深入浅出理解朴素贝叶斯算法

文章目录 引言一、朴素贝叶斯定理概述1.从贝叶斯定理说起2.朴素贝叶斯的“朴素”之处3.朴素贝叶斯算法的应用 二、朴素贝叶斯算法的优缺点三、python代码实现案例1.导入库2.数据预处理3.模型训练4.模型评估5.完整代码 四、总结 引言 朴素贝叶斯算法&#xff0c;一个听起来充满…

单口路由器多拨号ADSL实现方法

条件是多拨号场景&#xff0c;公司路由器接口不够用

unity基础——Navigation导航系统(补充)

1、Off Mesh Link 过渡动画设置 首先创建一个动画 关闭 Nav Mesh Agent 中的 Auto Traverse Off Mesh Link编写脚本 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI;public class OffMeshTest : MonoBehaviour {//Pl…

使用 NetworkX 进行图论分析与可视化

使用 NetworkX 进行图论分析与可视化 NetworkX 是一个用于创建、操作和研究复杂网络的 Python 库。它提供了丰富的图论算法和数据结构&#xff0c;适用于各种网络分析任务。本文将分点介绍 NetworkX 的主要功能&#xff0c;并通过代码示例进行详细说明。 1. 安装 NetworkX 在…