当前位置: 首页 > news >正文

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.lryc.cn/news/608422.html

相关文章:

  • 丝杆升降机在物流运输领域有哪些应用场景
  • 大模型Agent记忆的主流技术与优缺点解析
  • 23th Day| 39.组合总和,40.组合总和II,131.分割回文串
  • 数据结构---概念、数据与数据之间的关系(逻辑结构、物理结构)、基本功能、数据结构内容、单向链表(该奶奶、对象、应用)
  • 模型 古德哈特定律(Goodhart’s law)
  • 跨语言AI服务指标收集实战
  • 【深度学习】【三维重建】windows11环境配置PyTorch3d详细教程
  • 智能图书馆管理系统开发实战系列(五):前后端集成 - koffi调用与接口设计
  • WAIC引爆AI,智元机器人收购上纬新材,Geek+上市,157起融资撑起热度|2025年7月人工智能投融资观察 · 极新月报
  • FreeRTOS源码分析一:task启动(RISCV架构)
  • 【图像处理基石】用Python实现基础滤镜效果
  • PCB铜浆塞孔工艺流程
  • 网页操作自动化解决方案:如何用Browser-Use+CPolar提升企业运营效率
  • openwrt下安装istore(基于pve)
  • CCF IVC 2025“汽车安全攻防赛” -- Crypto -- WriteUp
  • ESP2025年6月认证C++八级( 第三部分编程题(2)遍历计数)
  • 线程池的实现
  • 【python】转移本地安装的python包
  • 【语音技术】意图与语料
  • 从下单到发货:如何清晰表达发货时间
  • Python编程基础与实践:Python条件语句入门:掌握if, else, 和elif
  • Android动画实现控件形状、大小逐渐过渡
  • Agentic RAG:自主检索增强生成的范式演进与技术突破
  • Waterfox水狐浏览器、火狐浏览器外观修改
  • XGBoost三部曲:XGBoost参数详解
  • Store / Slice / Reducer
  • 利用DeepSeek将Rust程序的缓冲输出改写为C语言实现提高输出效率
  • Python爬虫实战:研究SimpleCV技术,构建图像获取及处理系统
  • vulnhub-ELECTRICAL靶场攻略
  • 基于OAuth2与JWT的微服务API安全实战经验分享