一、java原生websocket
1.1基于标准规范
遵循JSR 356(Java EE 7+),需要应用服务器支持(如Tomcat 8+、Jetty 9+)。
1.2核心组件
- 注解驱动:使用
@ServerEndpoint
定义服务端端点,通过@OnOpen
、@OnMessage
、@OnClose
等注解处理事件。 - 编解码器:自定义
Encoder
/Decoder
处理消息与对象的转换。 - 配置类:通过
ServerEndpointConfig.Configurator
自定义握手逻辑或端点配置。
1.3特点
- 轻量级:直接操作底层API,适合对协议有精细控制需求的场景。
- 依赖容器:需运行在支持Java EE 7+的服务器中,配置相对繁琐。
- 无高级协议支持:需自行实现消息路由、订阅等逻辑。
1.4代码
import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
@ServerEndpoint("/chat")
public class ChatEndpoint {
private static final CopyOnWriteArraySet<Session> sessions = new CopyOnWriteArraySet<>();
@OnOpen
public void onOpen(Session session) {
sessions.add(session);
System.out.println(" 新连接:" + session.getId());
sendMessage(session, "欢迎加入聊天!");
}
@OnMessage
public void onMessage(String message, Session session) {
System.out.println(" 收到来自 " + session.getId() + " 的消息:" + message);
// 广播给所有客户端
for (Session s : sessions) {
sendMessage(s, "用户 " + session.getId() + " 说: " + message);
}
}
@OnClose
public void onClose(Session session, CloseReason reason) {
sessions.remove(session);
System.out.println(" 连接关闭:" + session.getId() + ",原因:" + reason.getReasonPhrase());
}
@OnError
public void onError(Session session, Throwable throwable) {
System.err.println(" 错误发生于连接 " + session.getId() + ": " + throwable.getMessage());
}
private void sendMessage(Session session, String msg) {
try {
session.getBasicRemote().sendText(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
二 、Spring WebSocket
2.1框架集成
Spring Framework 4+提供支持,与Spring MVC、Security等组件深度集成。
2.2核心组件
- 配置简化:通过
@EnableWebSocket
启用支持,或使用@EnableWebSocketMessageBroker
整合STOMP协议。 - 消息代理:支持基于内存(如RabbitMQ、ActiveMQ)的消息代理,实现订阅-发布模式。
- STOMP协议:通过
@MessageMapping
路由消息,类似HTTP的REST风格。 - 拦截器:提供
HandshakeInterceptor
处理握手前后逻辑,ChannelInterceptor
监控消息通道。
2.3特点
- 高层抽象:简化端点注册和消息处理,支持消息转换(如JSON到对象)。
- 安全性:集成Spring Security实现WebSocket的认证与授权。
- 跨域兼容性:通过
WebSocketTransportRegistration
配置跨域和消息限制。 - 客户端支持:提供
WebSocketClient
抽象,兼容多种实现(Tomcat、Jetty等)。
2.4代码
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
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;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Controller;
import org.springframework.web.socket.messaging.SessionConnectedEvent;
@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("/chat-websocket") // WebSocket连接端点
.withSockJS(); // 支持SockJS回退选项
}
}
@Controller
public class ChatController {
private final SimpMessagingTemplate messagingTemplate;
public ChatController(SimpMessagingTemplate messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
// 处理客户端发送的消息
@MessageMapping("/send") // 接收/app/send的消息
@SendTo("/topic/chat") // 广播到所有订阅/topic/chat的客户端
public String handleMessage(String message) {
return "用户说: " + message;
}
// 监听连接建立事件
@EventListener
public void handleWebSocketConnectListener(SessionConnectedEvent event) {
String sessionId = event.getMessage().getHeaders().get("simpSessionId").toString();
System.out.println("新连接: " + sessionId);
// 发送欢迎消息到当前客户端
messagingTemplate.convertAndSendToUser(
sessionId,
"/queue/welcome",
"欢迎加入聊天!"
);
}
// 监听连接断开事件
@EventListener
public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {
String sessionId = event.getSessionId();
System.out.println("连接关闭: " + sessionId);
// 通知其他用户该用户离开
messagingTemplate.convertAndSend(
"/topic/chat",
"用户 " + sessionId + " 已离开"
);
}
}
const socket = new SockJS('/chat-websocket');
const stompClient = Stomp.over(socket);
stompClient.connect({}, (frame) => {
// 订阅广播频道
stompClient.subscribe('/topic/chat', (message) => {
console.log('收到广播: ' + message.body);
});
// 订阅私有欢迎频道
stompClient.subscribe('/user/queue/welcome', (message) => {
console.log('系统消息: ' + message.body);
});
});
// 发送消息到服务端
function sendMessage() {
stompClient.send("/app/send", {}, "Hello World");
}
三、二者的区别
特性 | Java原生WebSocket | Spring WebSocket |
---|---|---|
协议支持 | 仅基础WebSocket,需自行扩展 | 支持STOMP,简化消息路由与广播 |
开发效率 | 需手动处理会话、路由,代码量较大 | 注解驱动,集成消息代理,开发效率高 |
安全性 | 需自定义实现 | 无缝整合Spring Security |
依赖与兼容性 | 依赖Java EE服务器 | 支持Spring Boot自动配置,跨容器兼容 |
适用场景 | 轻量级、低延迟或需直接控制协议的场景 | 复杂应用(如聊天、实时通知),需快速集成 |