SpringBoot 内嵌 Tomcat 的启动流程

Spring Boot 内嵌 Tomcat 的启动流程 ,本质上就是把"手动部署WAR包到外部Tomcat"这件事,变成通过Java代码在main方法里一键启动。

整个流程拆成三大阶段,用最通俗的话讲透:


阶段一:SpringApplication 启动,触发自动配置

当你点击运行@SpringBootApplication的main方法时:

  1. SpringApplication.run()开始执行核心刷新(refresh)容器。

  2. Spring Boot的自动配置机制 会扫描类路径,发现你依赖了spring-boot-starter-web,这会触发ServletWebServerFactoryAutoConfiguration配置类。

  3. 这个配置类会做一件事:创建一个内嵌Web服务器的工厂。

    • 默认情况下,因为Tomcat的依赖存在,它会创建TomcatServletWebServerFactory。

    • 这个工厂就是专门负责"生产"Tomcat服务器的。


阶段二:创建并配置 Tomcat 实例

这个阶段是整个流程的肉 ,它发生在refresh上下文时的onRefresh()方法里,具体步骤如下:

  1. 工厂开始构建 :TomcatServletWebServerFactory的getWebServer()方法被调用,此时会:

    • 实例化一个原生的org.apache.catalina.startup.Tomcat对象。

    • 设置基础目录(basedir),通常是操作系统的临时目录。

  2. 配置核心组件(Engine/Host/Context):

    • 创建Engine (引擎),默认名字叫"Tomcat"。

    • 创建Host (虚拟主机),默认是localhost,并设置应用根目录。

    • 最关键的一步 :创建Context (上下文)。这个Context代表你的整个Spring Boot应用,它的路径通常是空字符串""(即根路径)。

  3. 添加Servlet(即DispatcherServlet):

    • Spring Boot会创建一个DispatcherServlet的Bean。

    • 然后将这个Servlet动态添加 到刚才创建的Context中,并映射到"/"(即所有请求)。

    • 注意 :这里的添加并不是通过web.xml,而是通过编程方式调用Tomcat.addServlet()和Context.addServletMapping()。

  4. 设置端口和连接器:

    • 读取你配置文件里的server.port(默认8080),设置到Tomcat的Connector(连接器)上。

    • 默认使用NIO协议 (org.apache.coyote.http11.Http11NioProtocol)。

此时,Tomcat实例已经构建完毕,但还没有启动,只是准备好了。


阶段三:启动 Tomcat 并发布 ServletContext

这是最后的点火动作:

  1. 触发启动 :在refresh容器的最后一步(finishRefresh),会调用TomcatWebServer的start()方法。

  2. 内部启动链:

    • 调用Tomcat.start() -> 这会启动所有组件(Connector、Engine、Host、Context)。

    • 连接器(Connector)开始监听指定端口,准备接收HTTP请求。

    • 同时,会触发ServletContextInitializer回调,执行你所有的Filter、Listener的初始化。

  3. 发布事件 :启动成功后,Spring Boot会发布ServletWebServerInitializedEvent事件,表示内嵌服务器已就绪。

  4. 阻塞等待 :最后,TomcatWebServer会启动一个非守护线程(keepAlive),让主线程阻塞,保证Tomcat一直运行,等待请求进来。


核心时序图

与外部Tomcat部署的关键区别(面试加分点)

对比维度 外部Tomcat(传统WAR) Spring Boot 内嵌Tomcat
启动入口 由Tomcat脚本(catalina.sh)触发 由Java的main()方法触发
Servlet容器 独立进程,部署多个WAR 嵌入在JVM中,随应用启动和停止
Context创建方式 解析web.xml或注解扫描 编程式创建Context,并手动注册DispatcherServlet
类加载器 复杂的委派机制(Common/Shared/Webapp) 相对简单,直接使用应用类加载器(AppClassLoader)
适用场景 多应用共享Tomcat 微服务、云原生、独立运行
相关推荐
一只爱撸猫的程序猿1 小时前
我看着一个 AI 引擎在 14 天里,从"记忆"走进了"搜索"
人工智能·后端·架构
陈随易4 小时前
纯 Go 写的 JS 引擎,跑分超过了 C 语言的 QuickJS
前端·后端·程序员
Yyyyyy~5 小时前
【Java】Day4Web基础知识
java·spring boot
卷无止境5 小时前
RAGFlow 项目全景报告:从文档解析引擎到 Agent 原生数据库
后端·python
小Z先生5 小时前
我用 Go + 系统 WebView 写了个纯本地 Postman:不装 Electron、不连云端
后端·github
IT_陈寒6 小时前
Redis连接池泄漏那次,我差点把生产环境搞崩了
前端·人工智能·后端
灿飞屋6 小时前
Kotlin与Java虚拟机三:控制流
android·java·开发语言·后端·python·kotlin·安卓
石小石Orz6 小时前
AI 正在蚕食我们的编码能力
前端·后端·算法
陈随易7 小时前
专注飞机 FocusFlight,两个人把番茄钟做成了一趟航班
前端·后端·程序员
量化分析码农7 小时前
【Python量化波动率实战 04】低波动异象:低波组真的跑赢高波组吗
后端