Java WebSocket 核心原理与实战应用
本文介绍了 WebSocket 协议在 Java 中的应用。首先对比了 HTTP 轮询的局限性,阐述了 WebSocket 全双工通信的优势及握手原理。接着详细讲解了基于 Spring Boot 的环境搭建、配置方式以及服务端 Endpoint 的生命周期管理。随后展示了客户端 JavaScript 的实现逻辑,并通过实时聊天案例演示了消息广播功能。最后分析了兼容性、性能优化及安全性等常见问题及解决方案。

本文介绍了 WebSocket 协议在 Java 中的应用。首先对比了 HTTP 轮询的局限性,阐述了 WebSocket 全双工通信的优势及握手原理。接着详细讲解了基于 Spring Boot 的环境搭建、配置方式以及服务端 Endpoint 的生命周期管理。随后展示了客户端 JavaScript 的实现逻辑,并通过实时聊天案例演示了消息广播功能。最后分析了兼容性、性能优化及安全性等常见问题及解决方案。

在互联网应用中,HTTP 协议采用请求 - 响应模式,客户端发起请求,服务器返回响应。这种模式在大多数场景下表现良好,但在需要实时通信的场景(如在线聊天、股票行情)中显得力不从心。
为了实现实时通信,传统方式常使用轮询(Polling)。短轮询频繁发送请求,浪费资源且实时性差;长轮询虽有所改进,但服务器资源消耗大。例如在股票交易高峰期,大量轮询请求会让服务器不堪重负,导致数据延迟。
为了解决这些问题,WebSocket 协议应运而生。它实现了客户端和服务器之间的双向实时通信,让数据传输更加高效流畅。
WebSocket 是 HTML5 提供的一种在单个 TCP 连接上进行全双工通信的协议。全双工意味着客户端和服务器可以同时双向传输数据。相比 HTTP 的单向通信,WebSocket 允许服务端主动向客户端推送数据,真正实现了实时通信。
Upgrade: websocket 头部的请求,服务器返回 101 Switching Protocols 响应确认升级。
以 Spring Boot 项目为例,引入 WebSocket 依赖。
Maven (pom.xml):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
Gradle (build.gradle):
implementation 'org.springframework.boot:spring-boot-starter-websocket'
推荐实现 WebSocketMessageBrokerConfigurer 接口,避免继承 WebMvcConfigurationSupport 导致自动配置失效。
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket-endpoint")
.setAllowedOrigins("*")
.withSockJS();
}
}
注解式定义更为常用:
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
@Component
@ServerEndpoint("/websocket")
public class WebSocketServer {
@OnOpen
public void onOpen(Session session) {
System.out.println("新的连接建立:" + session.getId());
}
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("接收到客户端消息:" + message);
try {
session.getBasicRemote().sendText("服务器已收到你的消息:" + message);
} catch (Exception e) {
e.printStackTrace();
}
}
@OnClose
public void onClose(Session session) {
System.out.println("连接关闭:" + session.getId());
}
@OnError
public void onError(Session session, Throwable throwable) {
System.out.println("发生错误:" + throwable.getMessage());
throwable.printStackTrace();
}
}
@OnOpen:连接建立时调用,可初始化 Session。@OnMessage:处理接收到的消息,可解析业务逻辑并回复。@OnClose:连接关闭时调用,用于清理资源。@OnError:处理异常,记录日志或通知客户端。同步发送:session.getBasicRemote().sendText(message)
异步发送:session.getAsyncRemote().sendText(message)
前端使用 JavaScript 创建 WebSocket 对象:
var socket = new WebSocket('ws://localhost:8080/websocket');
socket.onopen = function(event) {
console.log('WebSocket 连接已建立');
socket.send('Hello, server!');
};
socket.onmessage = function(event) {
console.log('收到服务器消息:', event.data);
// 解析 JSON 并更新页面
};
socket.onclose = function(event) {
console.log('WebSocket 连接已关闭');
};
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@Component
@ServerEndpoint("/chat")
public class ChatServer {
private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<>());
@OnOpen
public void onOpen(Session session) {
sessions.add(session);
System.out.println("新用户连接:" + session.getId());
}
@OnMessage
public void onMessage(String message, Session sender) {
for (Session session : sessions) {
if (!session.equals(sender)) {
try {
session.getBasicRemote().sendText(sender.getId() + " 说:" + message);
} catch (IOException e) {
e.printStackTrace();
try {
sender.getBasicRemote().sendText("消息发送失败");
} catch (IOException ex) { ex.printStackTrace(); }
sessions.remove(session);
}
}
}
}
@OnClose
public void onClose(Session session) {
sessions.remove(session);
System.out.println( + session.getId());
}
{
System.out.println( + throwable.getMessage());
throwable.printStackTrace();
sessions.remove(session);
}
}
HTML 页面示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>实时聊天小工具</title>
<style>
#message-list { width: 400px; height: 300px; border: 1px solid #ccc; overflow-y: scroll; }
</style>
</head>
<body>
<div id="message-list"></div>
<input type="text" id="input-message" placeholder="请输入消息">
<button onclick="sendMessage()">发送</button>
<script>
var socket = new WebSocket('ws://localhost:8080/chat');
socket.onopen = () { .(); };
socket. = () {
list = .();
p = .();
p. = event.;
list.(p);
list. = list.;
};
() {
input = .();
(input..() !== ) {
socket.(input.);
input. = ;
}
}
旧版浏览器可能不支持 WebSocket。可使用 SockJS 作为兼容方案,它会自动回退到 XHR-streaming 等协议。
wss:// 协议。WebSocket 凭借全双工、低延迟特性,成为现代 Web 实时交互的首选协议。在 Java 开发中,结合 Spring Boot 可快速构建稳定高效的实时服务。实际应用中需注意兼容性、性能及安全问题,以确保系统可靠性。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online