6.3 WebSocket升级与Spring Boot内嵌


文档摘要

6.3 WebSocket 升级与 Spring Boot 内嵌 本节摘要:终点站的两个延伸形态。WebSocket 用一次特殊的 HTTP 握手把连接升级为全双工长通道,服务端可以主动推送;Spring Boot 则反转了部署关系——不再是应用住进 Tomcat,而是 Tomcat 被装进应用打成的一个可执行包。本节写一个最小 WebSocket 端点、讲清升级握手的两个要点,然后完整过一遍内嵌模式的配置方法与两种部署形态的取舍。 管道漫游的最后一站接待两类特殊旅客。前六章的请求模型都是"一问一答",WebSocket 打破它;前六章的部署模型都是"应用住进容器",Spring Boot 反转它。两者都是 Tomcat 生态的主流形态,终点站不讲它们就不完整。

6.3 WebSocket 升级与 Spring Boot 内嵌

本节摘要:终点站的两个延伸形态。WebSocket 用一次特殊的 HTTP 握手把连接升级为全双工长通道,服务端可以主动推送;Spring Boot 则反转了部署关系——不再是应用住进 Tomcat,而是 Tomcat 被装进应用打成的一个可执行包。本节写一个最小 WebSocket 端点、讲清升级握手的两个要点,然后完整过一遍内嵌模式的配置方法与两种部署形态的取舍。

管道漫游的最后一站接待两类特殊旅客。前六章的请求模型都是"一问一答",WebSocket 打破它;前六章的部署模型都是"应用住进容器",Spring Boot 反转它。两者都是 Tomcat 生态的主流形态,终点站不讲它们就不完整。

把 HTTP 连接升级成电话线

普通 HTTP 像传纸条:问一句答一句,答完各忙各的。WebSocket 像接通电话:握手之后双方随时说话,连接一直保持。升级动作用 HTTP 语法发起——一个带特殊头部的请求,服务端同意后原连接改走 WebSocket 帧协议,从此不再是一问一答。

// 服务端最小端点:连接建立 接收消息 回声 import jakarta.websocket.*; import jakarta.websocket.server.ServerEndpoint; import java.io.IOException; @ServerEndpoint("/ws/chat") public class ChatEndpoint { @OnOpen public void onOpen(Session session) { System.out.println("客户端接入 会话 " + session.getId()); } @OnMessage public String onMessage(String message) { // 返回值自动作为一条消息发回 客户端收到的就是它 return "服务端收到 " + message; } @OnClose public void onClose(Session session) { System.out.println("会话关闭 " + session.getId()); } @OnError public void onError(Session session, Throwable error) { error.printStackTrace(); } }

握手请求的两个要点:路径由注解声明,端口就是连接器端口——WebSocket 没有独立端口,它搭 HTTP 的车;升级请求头里带着约定字段,容器看到它就调出 WebSocket 处理器接管连接,此后这条连接脱离 3.1 的请求流水线(但仍在 maxConnections 的账上)。用浏览器控制台可以当场验证。

// 浏览器控制台直接跑 三行验证回声 const ws = new WebSocket('ws://localhost:8080/order/ws/chat'); ws.onmessage = e => console.log('收到 ' + e.data); ws.send('你好管道');
收到 服务端收到 你好管道

工程上两个注意。其一,会话对象线程安全但要自己管并发广播——给所有在线会话群发时遍历集合逐个发送,发送方法支持同步与异步两档,高频推送用异步档防止互相阻塞。其二,长连接改变了容量模型:3.2 的算术按"短请求"设计,换成几万条长连接后,连接容量与线程占用的关系重新洗牌,NIO 模型(一条连接不再占一个线程)在 WebSocket 场景下的优势比普通 HTTP 更明显——这也是 3.2 结论的又一次印证。

反转部署关系:Spring Boot 内嵌 Tomcat

传统模式是"容器等应用":装好 Tomcat,把 WAR 放进去。Spring Boot 模式是"应用带容器":构建产物是一个可执行包,里面打包了内嵌的 Tomcat,运行一条命令,应用自己就是服务进程。

<!-- 构建配置关键片段:打成可执行包并排除独立容器 --> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!-- 这个启动器默认引入内嵌 Tomcat 无需额外配置 --> </dependency> </dependencies>
# 应用配置文件:内嵌连接器三件套 语义与 server.xml 完全对应 server.port=8080 server.tomcat.threads.max=200 server.tomcat.accept-count=100
# 发布就是一条命令 启动日志里能看到熟悉的组件 java -jar order-service.jar
Tomcat initialized with port 8080 Tomcat started on port 8080 (http) with context path ''

关键认知:内嵌不等于另一款 Tomcat。3.2 的线程模型、4.1 的容器层级、5.1 的过滤器机制,全部原样生效,只是配置入口从 XML 换成了配置文件与代码。配置文件里那三行与 server.xml 里的三个属性一一对应——管道知识完全迁移,这是本册坚持以管道为主线讲述的最大红利。

两种形态怎么选?一张表说清。

维度 独立 Tomcat 加 WAR Spring Boot 内嵌
部署产物 WAR 包 可执行包
升级容器 换 Tomcat 目录即可,应用不动 要随应用重新构建发布
多应用共享实例 天然支持,资源集中 一应用一进程,资源独占
运维界面 成熟的脚本与日志体系 依赖应用自身与外挂运维
适用场景 多应用集中托管、遗留体系 微服务、云原生、快速交付

取舍的本质是"谁是最小交付单位"。最小单位是应用(微服务、容器化部署),内嵌模式顺流而下;最小单位是机器上的服务集合(传统企业机房、一台机器养多个应用),独立容器仍是正解。两种形态在本册的知识地图上位于同一条管道——变化的只是管道的包装方式。

💡 关键直觉:判断一个团队该用哪种形态,看他们的发布频率与交付单位。按天发布、按应用扩缩,内嵌;按月发布、按机器规划,独立容器。形态跟节奏走,不跟潮流走。

本节要点回顾

  • 升级不换端口:WebSocket 握手走 HTTP 语法,同端口同连接器,升级后连接脱离请求流水线但仍占连接额度。
  • 端点四回调:开、消息、关、错,注解声明路径,回声三行代码可现场验证。
  • 长连接改变容量账:NIO 的优势在 WebSocket 场景更明显,容量规划要重新算。
  • 内嵌是包装不是重写:连接器参数、容器层级、过滤器机制全部原样迁移,只是配置入口变了。
  • 形态跟交付单位走:应用为单位选内嵌,机器为单位选独立容器。

至此,请求从进城到终点的全部旅程走完。第 7 章转入回程与保养——怎么让这条管道跑得快、看得见、坏了好修、坏人进不来。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U