Spring Boot 内嵌 Tomcat 处理 HTTP 请求的全过程

我们来完整、准确地梳理一遍 Spring Boot 内嵌 Tomcat 处理 HTTP 请求的全过程,并澄清 I/O 模型的问题。


✅ 完整流程(从客户端到响应返回)

假设你用 java -jar myapp.jar 启动了一个 Spring Boot 应用(内嵌 Tomcat),浏览器发起请求:

1️⃣ 客户端 → 服务器:建立 TCP 连接

  • 客户端(如浏览器)向服务器 IP:8080 发起 TCP 三次握手
  • 成功后,TCP 连接建立(此时还没有任何 HTTP 数据)

2️⃣ 客户端发送 HTTP 请求数据

  • 在已建立的 TCP 连接上,客户端发送 原始 HTTP 报文 (字节流),例如:

    复制代码
    GET /api/user/1 HTTP/1.1
    Host: localhost:8080
    Accept: application/json

3️⃣ Tomcat 接收并解析 HTTP 请求

✅ 关键点:Tomcat 是 Servlet 容器,负责底层网络通信和 HTTP 协议解析

  • Tomcat 的 连接器(Connector) 监听 8080 端口
  • 接收 TCP 字节流 → 解析成 HttpServletRequest / HttpServletResponse 对象
  • 这一步与 Spring 无关,是 Tomcat 自己完成的(基于 Servlet 规范)

🔧 I/O 模型问题(BIO / NIO):

  • 传统 Tomcat(老版本默认):BIO(Blocking I/O)→ 每个请求一个线程,性能差
  • 现代 Spring Boot 内嵌 Tomcat(默认) :NIO(Non-blocking I/O) → 少量线程处理大量连接(基于 Java NIO 的 Selector 机制)
  • Tomcat 10+ 还支持 NIO2(AIO)和 APR(本地库)

✅ 所以你说的"bno"很可能是 "BIO" 的误打,而实际情况是:现代 Spring Boot 默认用的是 NIO!

4️⃣ 请求交给 Spring MVC 处理

  • Tomcat 将 HttpServletRequest 交给 Spring 的 DispatcherServlet
  • Spring MVC 开始工作:
    • HandlerMapping :找到对应的 @Controller 方法
    • HandlerAdapter :调用你的业务方法(如 @GetMapping("/api/user/{id}"))
    • 参数解析:路径变量、JSON 转对象(使用 Jackson 等)
    • 执行你的业务逻辑(Service、DAO、Redis、DB 等)

5️⃣ 构建 HTTP 响应

  • 你的 Controller 方法返回对象(如 User)
  • Spring 用 HttpMessageConverter (如 MappingJackson2HttpMessageConverter)将其序列化为 JSON 字符串
  • 写入 HttpServletResponse 的输出流

6️⃣ Tomcat 发送响应 + 断开连接

  • Tomcat 将响应组装成 HTTP 报文(含状态行、Header、Body)
  • 通过同一个 TCP 连接发送回客户端
  • 根据 Connection 头决定是否保持连接 (HTTP/1.1 默认 keep-alive):
    • 如果是 短连接 (或客户端发了 Connection: close)→ 四次挥手断开 TCP
    • 如果是 长连接 → 连接保持,等待下一个请求(或超时后关闭)

📌 关键澄清

你提到的说法 实际情况
"Tomcat 解析 HTTP 请求" ✅ 正确,这是 Tomcat 的核心职责
"其实是 bno" ❌ 应为 NIO (非阻塞 I/O),不是 BIO(阻塞 I/O)
Spring Boot 默认 I/O 模型 NIO (通过内嵌 Tomcat 的 NioEndpoint 实现)

💡 你可以通过日志确认:

Spring Boot 启动时会打印:
Tomcat initialized with port(s): 8080 (http)

并且底层使用的是 org.apache.tomcat.util.net.NioEndpoint


✅ 总结全流程(简化版)

复制代码
客户端
  │
  ▼
TCP 三次握手(建立连接)
  │
  ▼
发送 HTTP 请求字节流
  │
  ▼
Tomcat (NIO) 接收 → 解析为 HttpServletRequest
  │
  ▼
Spring MVC DispatcherServlet 分发请求
  │
  ▼
执行 @Controller 业务逻辑
  │
  ▼
返回结果 → 序列化为 JSON
  │
  ▼
Tomcat 写入 HttpServletResponse → 发送 HTTP 响应
  │
  ▼
根据 Connection 头决定:
   ├─ keep-alive → 保持 TCP 连接(长连接)
   └─ close     → TCP 四次挥手断开(短连接)

如果你对 NIO 的工作原理 (Selector、Channel、Buffer)或者 Spring Boot 如何配置 Tomcat 的连接参数(如最大连接数、超时时间)感兴趣,也可以继续深入!

相关推荐
她的男孩17 分钟前
企业接口照样拦得住:独立 Flyway、@RequiresFeature 与离线许可证
java·spring boot·后端
十年Java程序媛18 分钟前
Lambda 与函数式接口|别只会复制 ()->{},底层规则和坑一次性讲清
java·spring boot·后端
马剑威(威哥爱编程)2 小时前
【AI全栈后端12-11】Spring Boot 把 AI 接口真正上线扛量:限流 / 降级 / 可观测
人工智能·spring boot·后端
RuoyiOffice2 小时前
SpringBoot+Vue3+Onlyoffice 企业文件生命周期:上传、业务关联、权限、版本与安全清理
spring boot·vue3·文件管理·对象存储·权限控制·ruoyi office·附件管理
阿狗童鞋3 小时前
高并发系统设计实战指南
java·spring boot·spring cloud
十年Java程序媛17 小时前
Java 接口和抽象类对比|Java8 新特性,抛弃老旧八股,正确选型
java·spring boot·后端
长按助力退休19 小时前
HTTP缓存从强缓存到协商缓存,前端性能优化第一步
http
for_ever_love__19 小时前
MySQL 高频面试题 30 问:索引、事务、锁、日志、主从与分库分表(MySQL 8.0 版)
java·数据库·spring boot·mysql·spring cloud·面试·总结
SL_staff19 小时前
设备越多系统越崩?根源在三层抽象失效
spring boot·物联网·github
威哥爱编程19 小时前
【AI全栈12-01】Spring Boot 为何是 AI 全栈后端优选
java·spring boot·后端