文章目录
- 1. 准备阶段:应用启动的入口
- 2. 创建 SpringApplication 对象:开始启动工作
- 3. 配置环境(Environment):识别开发环境与生产环境
- 4. 启动监听器和初始化器:感知启动的关键事件
- 5. 创建 ApplicationContext 容器:加载核心 Bean
- 6. 自动配置(Auto-Configuration):自动加载所需 Bean
- 7. 启动内嵌 Web 服务器:Tomcat、Jetty、Undertow
- 8. 执行 CommandLineRunner 和 ApplicationRunner
- 9. 启动完成:应用已准备好接收请求
- 总结
- 推荐阅读文章
Spring Boot 是一个帮助 Java 开发者快速搭建和启动应用的框架。了解它的启动过程,可以帮助我们深入理解 Spring Boot 的工作原理,尤其是它如何将配置、组件扫描、自动配置等内容串联起来。我们用一个直观的流程来解读 Spring Boot 的启动过程。
1. 准备阶段:应用启动的入口
Spring Boot 应用程序的启动通常从一个 main
方法开始(在 Application
类中)。这个 main
方法会调用 SpringApplication.run(Application.class, args)
,其实就是从这一步开始启动整个应用。
流程描述:
- 你可以把
SpringApplication.run()
理解为一个“开关”,它会启动一连串的动作。 - 一旦调用
run()
,Spring Boot 就会进入自动化启动的“准备阶段”。
2. 创建 SpringApplication 对象:开始启动工作
SpringApplication.run()
会首先创建一个 SpringApplication
对象。这个对象可以看作是启动应用的“总指挥”,主要负责:
- 设置应用的环境(Environment),比如是否是开发环境、生产环境等。
- 加载初步配置。
- 为后续的步骤做准备工作,比如准备监听器、事件发布等。
小贴士:在这个阶段,Spring Boot 会检查一些常见的配置文件(如 application.properties
或 application.yml
),并准备将这些配置信息应用到启动流程中。
3. 配置环境(Environment):识别开发环境与生产环境
Spring Boot 的 SpringApplication
对象会进一步去配置环境。比如,通过读取配置文件或者系统属性,它能识别应用当前是在开发环境还是生产环境,并根据不同环境做适当的优化。
案例:
- 假设你在
application.yml
中配置了spring.profiles.active=dev
,Spring Boot 会加载适用于dev
环境的配置。 - 这种分环境的配置机制,让应用在开发和生产之间可以无缝切换。
4. 启动监听器和初始化器:感知启动的关键事件
Spring Boot 启动过程中,还会初始化一些监听器(Listeners)和初始化器(Initializers)。它们的作用是“监听”启动过程中的各个步骤,并在关键时刻触发特定的逻辑。
案例:
- 你可以注册一个监听器,在 Spring Boot 启动时触发一些定制的行为,比如打印系统信息、记录日志等。
效果:
- 这种机制帮助开发者对启动过程拥有更高的可控性,也可以在启动时执行一些初始化工作。
5. 创建 ApplicationContext 容器:加载核心 Bean
这个步骤中,Spring Boot 会启动 ApplicationContext(应用上下文),它可以理解为一个容器,负责管理应用中的所有 Bean。
加载过程:
- ApplicationContext 会扫描项目中被
@Component
、@Service
、@Repository
等注解标记的类,把它们注册为 Bean。 - Spring Boot 还会根据自动配置(Auto-Configuration),加载额外的 Bean。比如,发现项目里有数据库依赖时,自动配置会加载数据库连接池的相关 Bean。
案例:
- 当你用
@SpringBootApplication
注解启动项目时,自动配置会根据类路径下的依赖,比如spring-boot-starter-web
,帮你自动加载 Web 服务器的相关配置和 Bean。
6. 自动配置(Auto-Configuration):自动加载所需 Bean
自动配置是 Spring Boot 启动的核心亮点。Spring Boot 会检测项目中的依赖项,并根据依赖,自动加载对应的配置。比如:
- 如果有 Web 相关的依赖(如
spring-boot-starter-web
),Spring Boot 会自动配置一个内嵌的 Tomcat 服务器。 - 如果项目中有数据库相关的依赖(如
spring-boot-starter-data-jpa
),它会自动加载数据源、事务管理等 Bean。
案例:
- 假设项目中添加了一个 Redis 依赖(如
spring-boot-starter-data-redis
),Spring Boot 会自动配置 Redis 连接池、RedisTemplate 等 Bean,免去了手动配置的麻烦。
7. 启动内嵌 Web 服务器:Tomcat、Jetty、Undertow
如果你的项目是一个 Web 项目(包含 Web 依赖),Spring Boot 会启动一个内嵌的 Web 服务器,比如 Tomcat。这个步骤会绑定端口(默认是 8080),并启动一个 Web 服务,准备接收 HTTP 请求。
效果:
- Spring Boot 的内嵌服务器特性,让我们无需安装和配置外部服务器,这也是 Spring Boot 应用可以直接运行的原因之一。
8. 执行 CommandLineRunner 和 ApplicationRunner
在 Spring Boot 的启动流程最后,如果项目里实现了 CommandLineRunner
或 ApplicationRunner
接口的 Bean,那么这些 Bean 的 run()
方法会被调用,执行启动后的收尾工作。
案例:
- 例如,你可以实现一个
CommandLineRunner
,在项目启动完成后执行一些初始化操作,比如从数据库加载默认数据,或检查系统状态等。
9. 启动完成:应用已准备好接收请求
到这里,Spring Boot 的启动流程基本完成。你的应用已经启动,所有配置已加载、Bean 已注册,服务也在监听端口等待请求。整个启动过程就是一个自动化和配置化的过程,让你专注业务代码,而不需要为每个 Bean、每个组件的配置费心。
总结
Spring Boot 的启动过程可以理解为九个关键步骤:
-
启动入口:调用
SpringApplication.run()
,启动流程。 - 创建 SpringApplication 对象:做启动前的准备。
- 配置环境:识别开发环境与生产环境。
- 启动监听器和初始化器:处理关键事件。
- 创建 ApplicationContext 容器:加载 Bean。
- 自动配置:根据依赖自动加载相关配置。
- 启动 Web 服务器:若是 Web 项目,启动内嵌服务器。
- 执行 CommandLineRunner / ApplicationRunner:启动后执行收尾工作。
- 启动完成:应用准备好,开始接收请求。
Spring Boot 的启动过程充分展示了其“约定优于配置”的理念,极大简化了 Java 项目的启动流程。希望这篇文章能帮助你对 Spring Boot 的启动过程有更清晰的认识!
推荐阅读文章
-
由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)
-
如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系
-
HTTP、HTTPS、Cookie 和 Session 之间的关系
-
什么是 Cookie?简单介绍与使用方法
-
什么是 Session?如何应用?
-
使用 Spring 框架构建 MVC 应用程序:初学者教程
-
有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误
-
如何理解应用 Java 多线程与并发编程?
-
把握Java泛型的艺术:协变、逆变与不可变性一网打尽
-
Java Spring 中常用的 @PostConstruct 注解使用总结
-
如何理解线程安全这个概念?
-
理解 Java 桥接方法
-
Spring 整合嵌入式 Tomcat 容器
-
Tomcat 如何加载 SpringMVC 组件
-
“在什么情况下类需要实现 Serializable,什么情况下又不需要(一)?”
-
“避免序列化灾难:掌握实现 Serializable 的真相!(二)”
-
如何自定义一个自己的 Spring Boot Starter 组件(从入门到实践)
-
解密 Redis:如何通过 IO 多路复用征服高并发挑战!
-
线程 vs 虚拟线程:深入理解及区别
-
深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别
-
10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!
-
“打破重复代码的魔咒:使用 Function 接口在 Java 8 中实现优雅重构!”
-
Java 中消除 If-else 技巧总结
-
线程池的核心参数配置(仅供参考)
-
【人工智能】聊聊Transformer,深度学习的一股清流(13)
-
Java 枚举的几个常用技巧,你可以试着用用
-
由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)
-
如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系
-
HTTP、HTTPS、Cookie 和 Session 之间的关系
-
使用 Spring 框架构建 MVC 应用程序:初学者教程
-
有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误
-
Java Spring 中常用的 @PostConstruct 注解使用总结
-
线程 vs 虚拟线程:深入理解及区别
-
深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别
-
10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!
-
探索 Lombok 的 @Builder 和 @SuperBuilder:避坑指南(一)
-
为什么用了 @Builder 反而报错?深入理解 Lombok 的“暗坑”与解决方案(二)