SpringBoot启动项目详解

SpringBoot 的启动过程是一个整合 Spring 核心容器、自动配置、嵌入式服务器等功能的复杂流程,核心目标是 “简化配置、快速启动”。下面从入口类开始,逐步拆解其详细启动步骤:

一、启动入口:@SpringBootApplicationmain方法

SpringBoot 应用的启动入口是一个带有@SpringBootApplication注解的类,其中的main方法是程序的起点:

@SpringBootApplication
public class MyApplication {public static void main(String[] args) {// 核心启动方法SpringApplication.run(MyApplication.class, args);}
}

这行代码看似简单,却包含了初始化 Spring 容器、触发自动配置、启动嵌入式服务器等一系列操作。

二、@SpringBootApplication注解的核心作用

@SpringBootApplication是一个 “复合注解”,它整合了三个关键注解,为启动过程奠定基础:

  1. @SpringBootConfiguration:本质是@Configuration,标识当前类是一个配置类,允许通过@Bean定义 Bean。
  2. @ComponentScan:自动扫描当前类所在包及其子包下的@Component(包括@Service@Controller等)注解类,将其注册为 Spring Bean。
  3. @EnableAutoConfiguration:SpringBoot 的 “灵魂”,开启自动配置功能,通过加载预设的配置类,自动配置 DataSource、Web 服务器等组件。

三、SpringApplication.run()的详细流程

SpringApplication.run(MyApplication.class, args)是启动的核心方法,可拆解为两大阶段SpringApplication实例初始化 + run()方法执行。

阶段 1:SpringApplication实例初始化(准备工作)

当调用SpringApplication.run(...)时,首先会创建SpringApplication实例,完成一系列初始化操作:

// 简化的初始化逻辑
public SpringApplication(Class<?>... primarySources) {this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));// 1. 推断应用类型(Servlet/Reactive/Native)this.webApplicationType = WebApplicationType.deduceFromClasspath();// 2. 加载初始化器(ApplicationContextInitializer)setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 3. 加载监听器(ApplicationListener)setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 4. 推断main方法所在的主类this.mainApplicationClass = deduceMainApplicationClass();
}

关键操作解析:

  • 推断应用类型:通过类路径中是否存在ServletReactive相关类,判断是传统 Web 应用(SERVLET)、响应式 Web 应用(REACTIVE)还是非 Web 应用(NONE)。
  • 加载初始化器:从META-INF/spring.factories文件中读取ApplicationContextInitializer实现类(用于初始化 Spring 上下文)。
  • 加载监听器:同样从spring.factories中读取ApplicationListener实现类(用于监听启动过程中的事件,如环境准备完成、容器刷新等)。
阶段 2:run()方法执行(核心启动流程)

run()方法是启动的核心,包含 12 个关键步骤,按顺序执行如下:

步骤 1:启动计时器(记录启动时间)
StopWatch stopWatch = new StopWatch();
stopWatch.start(); // 开始计时

用于统计应用启动总耗时,最终会在控制台输出(如Started MyApplication in 2.345 seconds)。

步骤 2:初始化运行监听器(SpringApplicationRunListeners

通过SpringFactoriesLoader加载SpringApplicationRunListener实现类(默认是EventPublishingRunListener),用于在启动各阶段发布事件(如ApplicationStartingEventApplicationEnvironmentPreparedEvent等),触发对应监听器的逻辑。

步骤 3:准备环境(Environment

创建并配置Environment(环境对象),包含:

  • 系统环境变量、JVM 参数、命令行参数(args)。
  • 配置文件(application.properties/application.yml)中的属性。
  • 激活的profiles(如dev/test/prod)。

过程:

  1. 为不同应用类型(Servlet/Reactive)创建对应Environment实例(如StandardServletEnvironment)。
  2. 加载配置文件:默认从classpath:classpath:/config/file:./file:./config/等路径读取。
  3. 处理命令行参数:将args中的参数(如--server.port=8081)添加到环境中,优先级最高。
步骤 4:打印 Banner(启动图标)

默认会在控制台打印 SpringBoot 的 Banner 图标(可通过spring.banner.location自定义,或设置spring.main.banner-mode=off关闭)。

步骤 5:创建ApplicationContext(Spring 容器)

根据应用类型创建对应的ApplicationContext(Spring 核心容器):

  • Servlet 应用AnnotationConfigServletWebServerApplicationContext
  • Reactive 应用AnnotationConfigReactiveWebServerApplicationContext
  • 非 Web 应用AnnotationConfigApplicationContext

ApplicationContext是 Spring 的 “大脑”,负责管理 Bean 的生命周期、依赖注入等核心功能。

步骤 6:准备ApplicationContext(上下文预处理)

为容器设置环境、注册 Bean、应用初始化器等:

  1. 将步骤 3 中准备好的Environment设置到容器中。
  2. 调用所有ApplicationContextInitializerinitialize()方法,对容器进行自定义初始化(如添加属性源、修改配置等)。
  3. 发布ApplicationContextInitializedEvent事件,通知监听器容器已初始化。
  4. 注册主配置类:将@SpringBootApplication标注的类(如MyApplication)注册为 Spring 的配置类。
步骤 7:刷新ApplicationContext(容器核心初始化)

这是 Spring 容器的核心步骤(继承自 Spring 的AbstractApplicationContext),包含 Bean 的扫描、加载、实例化等关键操作,具体包括:

7.1 执行BeanFactory的前置处理

初始化容器的BeanFactory(如DefaultListableBeanFactory),用于管理 BeanDefinition(Bean 的元数据)。

7.2 执行BeanFactoryPostProcessor(Bean 工厂后置处理器)

最关键的是自动配置类的加载
@EnableAutoConfiguration通过@Import(AutoConfigurationImportSelector.class)导入自动配置类。AutoConfigurationImportSelector会从META-INF/spring.factories中读取EnableAutoConfiguration对应的配置类(如DataSourceAutoConfigurationWebMvcAutoConfiguration等),并根据@Conditional条件注解(如@ConditionalOnClass@ConditionalOnMissingBean)筛选出符合当前环境的配置类,注册为 BeanDefinition。

7.3 注册BeanPostProcessor(Bean 后置处理器)

用于在 Bean 实例化前后进行增强(如 AOP 代理、依赖注入等)。

7.4 初始化消息源(国际化支持)
7.5 初始化事件多播器(用于事件发布)
7.6 初始化容器特定 Bean(子类扩展点)

对 Web 应用而言,这里会触发嵌入式服务器的创建与启动
ServletWebServerApplicationContextonRefresh()方法中调用createWebServer(),根据类路径中的依赖(如spring-boot-starter-tomcat)创建对应的服务器(Tomcat/Undertow/Jetty),并绑定端口(默认 8080)。

7.7 注册监听器到容器
7.8 完成 BeanFactory 初始化(实例化所有非懒加载单例 Bean)

容器会遍历所有 BeanDefinition,实例化单例 Bean(@Lazy标注的除外),并执行依赖注入(@Autowired)、初始化方法(@PostConstructInitializingBean)等。

7.9 发布容器刷新完成事件(ContextRefreshedEvent
步骤 8:刷新后的操作
  • 清除缓存(如类加载缓存)。
  • 发布ApplicationStartedEvent事件(通知容器已刷新完成)。
步骤 9:执行Runner(自定义启动逻辑)

调用所有ApplicationRunnerCommandLineRunnerrun()方法,执行启动后的自定义逻辑(如加载初始数据、检查配置等):

  • ApplicationRunner:接收ApplicationArguments参数(解析后的命令行参数)。
  • CommandLineRunner:直接接收原始String[] args参数。
步骤 10:发布启动完成事件

发布ApplicationReadyEvent事件,通知应用已完全启动,可对外提供服务。

步骤 11:停止计时器
stopWatch.stop(); // 停止计时
步骤 12:输出启动日志

打印启动成功日志,包含总耗时、活跃 Profiles 等信息(如Started MyApplication in 2.345 seconds (JVM running for 3.123))。

四、核心机制总结

  1. 自动配置:通过@EnableAutoConfigurationspring.factories中的配置类,根据依赖和环境自动配置组件(如 DataSource、Web 服务器)。
  2. 嵌入式服务器:在容器刷新阶段自动创建并启动(如 Tomcat),无需手动部署到外部服务器。
  3. 事件驱动:通过SpringApplicationRunListenerApplicationListener在启动各阶段发布事件,支持扩展(如自定义监听器处理特定阶段逻辑)。
  4. 简化配置:默认扫描路径、默认配置文件、默认 Bean 注册,减少手动配置。

五、流程图总结

main() → SpringApplication实例化 → run()↓
初始化监听器 → 准备环境(配置+参数) → 打印Banner → 创建ApplicationContext↓
准备上下文(设置环境+注册配置类) → 刷新上下文(核心)↓├─ 加载自动配置类 → 注册BeanDefinition├─ 实例化单例Bean → 依赖注入└─ 启动嵌入式服务器(如Tomcat)↓
执行Runner → 发布启动完成事件 → 输出启动日志

通过这一系列流程,SpringBoot 实现了 “零配置(或极简配置)” 的快速启动,让开发者专注于业务逻辑而非框架配置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/91757.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/91757.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PCB 控深槽如何破解 5G 基站 120℃高热魔咒?

5G 基站在高频通信下的功耗较 4G 基站提升 3-4 倍&#xff0c;射频模块、电源单元等核心部件的工作温度常突破 120℃&#xff0c;远超设备安全阈值&#xff08;≤85℃&#xff09;&#xff0c;形成制约通信稳定性的 “高热魔咒”。印制线路板&#xff08;PCB&#xff09;作为热…

NEXT.js 打包部署到服务器

在网上查了一下&#xff0c;记录一下1.首先执行打包命令&#xff0c;我这个项目是用的pnpm&#xff0c;可以根据项目需求使用 npm 或者别的pnpm run build2.打包完成后会有一个 .next 的文件夹&#xff0c;需要把下图的这些文件放到服务器。服务器需要有node环境之后就需要执行…

【AI分析】uv库自动安装脚本uv-installer-0.8.3.ps1分析

目录uv 安装脚本完整分析报告1. 脚本概述2. 参数解析3. 环境变量控制4. 核心函数详解a. Install-Binary&#xff08;主控函数&#xff09;b. Get-TargetTriple&#xff08;架构检测&#xff09;c. Download&#xff08;下载处理&#xff09;d. Invoke-Installer&#xff08;安装…

etcd 的安装与使用

介绍 Etcd 是一个 golang 编写的分布式、高可用的一致性键值存储系统&#xff0c;用于配置共享和服 务发现等。它使用 Raft 一致性算法来保持集群数据的一致性&#xff0c;且客户端通过长连接 watch 功能&#xff0c;能够及时收到数据变化通知&#xff0c;相较于 Zookeeper 框…

conda : 无法将“conda”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正

详细问题 PS C:\Users\wh109> conda init powershell conda : 无法将“conda”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写&#xff0c;如果包括路径&#xff0c;请确保路径正 确&#xff0c;然后再试一次。 所在位置 行:1 字符: 1conda init pow…

HQChart实战教程58:K线主图仿TradingView实现

本文将详细介绍如何使用HQChart实现类似TradingView风格的K线主图,包含完整的代码实现和详细注释,适合金融图表开发者和量化交易爱好者阅读。 一、TradingView风格特点分析 在开始实现前,我们先分析TradingView的K线主图核心特点: 简洁现代的UI设计:深色背景、清晰的网格…

GitPython08-源码解读

GitPython08-源码解读 1-核心知识 1&#xff09;gitPython核心代码很多都是对git命令返回的结果进行解析&#xff0c;在此补充git命令的返回内容2&#xff09;git ls-tree -> 查看某个提交或分支所对应的目录树3&#xff09;源码中Tree对应的业务逻辑 -> 获取git ls-tre…

中科院开源HYPIR图像复原大模型:1.7秒,老照片变8K画质

目录 前言 一、告别“龟速”艺术家&#xff0c;拥抱“闪电”打印机 二、不止是高清&#xff1a;它看得懂文字&#xff0c;更能理解你的心意 2.1 首先&#xff0c;它是位“文字保卫者” 2.2 其次&#xff0c;它还是个“细节创造家” 2.3 最后&#xff0c;它是一个能“听懂…

设计Mock华为昇腾GPU的MindSpore和CANN的库的流程与实现

在没有华为昇腾GPU可用的情况下用C库写一个Mock MindSpore和CANN的库&#xff0c;调用多核CPU和内存的资源来模拟GPU的算力&#xff0c;调试MindSpore和CANN的C代码&#xff0c;做这个库的基本流程步骤和详细设计是什么&#xff1f; 要创建一个Mock库来模拟华为昇腾GPU&#xf…

【AI问答记录】grafana接收query请求中未携带step参数,后端基于intervalMs和maxDataPoints等参数计算step的逻辑

让我详细分析Grafana源码中计算step的完整逻辑&#xff0c;它确实比简单的intervalMs/1000复杂得多。 完整的Step计算流程 1. 入口点&#xff1a;[models.Parse](file://F:\JavaProject\grafana-release-11.2.0\pkg\promlib\models\query.go#L190-L274)函数 在pkg/promlib/mode…

再谈亚马逊云科技(AWS)上海AI研究院7月22日关闭事件

【科技明说 &#xff5c; 科技热点关注】亚马逊云科技&#xff08;AWS&#xff09;上海AI研究院已于2025年7月22日正式解散&#xff0c;这是亚马逊在全球范围内的最后一个海外研究中心的关闭。这个消息是否是真的&#xff0c;目前得到的印证来自其研发中心的首席科学家王敏捷在…

Python中的决策树机器学习模型简要介绍和代码示例(基于sklearn)

一、决策树定义 决策树是一种监督学习算法&#xff0c;可用于**分类&#xff08;Classification&#xff09;和回归&#xff08;Regression&#xff09;**任务。 它的结构类似树状结构&#xff1a; 内部节点&#xff1a;特征条件&#xff08;如X > 2&#xff09;叶子节点&am…

Redis集群分布式(Redis Cluster)底层实现原理详细介绍

文章目录一、Redis集群概念二、集群节点1. 节点如何启动2. 节点的集群数据结构2.1 clusterNode结构2.2 clusterLink结构2.3 clusterState结构3. 节点如何加入集群三、数据分片机制1. 记录节点的槽指派信息2. 传播节点的槽指派信息3. 记录集群所有槽的指派信息4. 节点的槽指派命…

【走遍美国精讲笔记】第 1 课:林登大街 46 号

ACT 1-1 “我可以给您和您的小男孩拍张照吗&#xff1f;” 【故事梗概】 自由摄影艺术家 Richard Stewart&#xff0c;正在为编出自己的影集《走遍美国》到处拍照。今天他在由纽约市曼哈顿区到斯塔滕岛的渡船上工 作&#xff0c;回程中遇到了来自加州的一位黑人妇女 Martha Van…

Java中Lambda 表达式的解释

从 Java 8 开始&#xff0c;Lambda 表达式成为 Java 的一等公民。它不仅让代码更简洁&#xff0c;还为函数式编程打开了大门。如果你还没真正理解或使用过 Lambda&#xff0c;这篇文章就是为你写的。一、什么是 Lambda 表达式&#xff1f;Lambda 表达式是 Java 中的一种匿名函数…

Spring AI调用Embedding模型返回HTTP 400:Invalid HTTP request received分析处理

调用Embedding模型失败 Spring AI项目使用的Embedding模型是公司平台部署的&#xff0c;请求模型服务的时候报错&#xff0c;返回了HTTP 400 - Invalid HTTP request received错误。然后换成云厂商在线Embedding模型地址&#xff0c;正常调通。我用Apifox直接调用公司的模型服务…

Pytorch-02数据集和数据加载器的基本原理和基本操作

1. 为什么要有数据集类和数据加载器类&#xff1f; 一万个人会有一万种获取并处理原始数据样本的代码&#xff0c;这会导致对数据的操作代码标准不一&#xff0c;并且很难复用。为了解决这个问题&#xff0c;Pytorch提供了两种最基本的数据相关类&#xff1a; torch.utils.data…

无图形界面的CentOS 7网络如何配置

进入虚拟机输入ip addr命令&#xff1a;从 ip addr命令的输出可以明确看出 ​​lo和 ens33是两个不同的网络接口&#xff08;网卡&#xff09;lo&#xff08;回环接口&#xff09;​​​​作用​​&#xff1a;虚拟的本地回环网卡&#xff0c;用于本机内部通信&#xff08;如 1…

机器学习之线性回归的入门学习

线性回归是一种监督学习算法&#xff0c;用于解决回归问题。它的目标是找到一个线性关系&#xff08;一条直线或一个超平面&#xff09;&#xff0c;能够最好地描述一个或多个自变量&#xff08;特征&#xff09;与一个因变量&#xff08;目标&#xff09;之间的关系。利用回归…

2-5 Dify案例实践—利用RAG技术构建企业私有知识库

目录 一、RAG技术的定义与作用 二、RAG技术的关键组件 三、RAG技术解决的问题 四、RAG技术的核心价值与应用场景 五、如何实现利用RAG技术构建企业私有知识库 六、Dify知识库实现详解 七、创建知识库 1、创建知识库 2、上传文档 3、文本分段与清洗 4、索引方式 5、…