RSocket vs WebSocket:Spring Boot 3.3 中的两大实时通信利器
随着现代互联网应用的不断发展,实时通信已经成为许多应用程序不可或缺的功能。无论是社交网络、在线游戏还是数据监控系统,实时通信都能提供快速、无缝的信息交换。而实现实时通信的两种主要协议是 RSocket 和 WebSocket。
RSocket 是一种新的、先进的应用层协议,旨在提供高效的网络通信。与传统的请求/响应模式不同,RSocket 支持请求-响应、请求-流、流-流等多种模式,从而在微服务和流式数据传输中表现得更加灵活和高效。RSocket 的优势在于它可以在 TCP、WebSocket 等多种传输协议上运行,支持背压机制和多路复用,从而避免了资源的浪费,并保证了消息传递的可靠性。
WebSocket 是一种标准协议,允许客户端和服务器之间建立持久连接,客户端和服务器都可以主动发送消息。相较于传统的 HTTP 请求-响应模型,WebSocket 是全双工通信,即服务器可以实时向客户端推送数据,而不需要等待客户端发起请求,尤其适合实时数据更新场景。WebSocket 的使用场景广泛,涵盖了即时通讯、实时数据展示和多人在线游戏等。
运行效果:
若想获取项目完整代码以及其他文章的项目源码,且在代码编写时遇到问题需要咨询交流,欢迎加入下方的知识星球。
本文将结合 Spring Boot 3.3,详细讲解如何使用 RSocket 和 WebSocket 实现实时通信。我们将通过一个完整的示例,展示前后端交互、消息传递和双向通信的实际应用。文章还将结合具体的代码示例,演示如何从前端向后端发送消息,并在点击按钮时与服务器进行交互。
项目配置
项目依赖配置(pom.xml)
在 pom.xml
中引入 RSocket、WebSocket 以及其他必要的依赖。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.icoderoad</groupId> <artifactId>rsocket-websocket-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>rsocket-websocket-demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency><!-- Spring Boot Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- RSocket 支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-rsocket</artifactId> </dependency> <!-- WebSocket 支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <!-- Thymeleaf 模板引擎 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- Lombok 支持 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
应用配置(application.yml)
server port8080 spring rsocket server port7000 transport websocket mapping-path /rsocket websocket enabledtrue mapping /ws app rsocket-message"这是来自 RSocket 的消息" websocket-message"这是来自 WebSocket 的消息"
读取配置类 (RSocket 和 WebSocket 配置类)
我们使用 @ConfigurationProperties
注解读取配置文件中的 app
节点。这里使用 Lombok 来简化实体类的代码实现。
package com.icoderoad.rwebsocket.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; prefix = "app") (public class AppProperties { private String rsocketMessage; private String websocketMessage; }
RSocket 服务端实现
RSocket 提供了灵活的通信模型,允许服务端和客户端以流的方式交换数据。我们通过 @MessageMapping
来定义接收和处理客户端消息的方法。
package com.icoderoad.rwebsocket.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.stereotype.Controller; import com.icoderoad.rwebsocket.config.AppProperties; import reactor.core.publisher.Mono; public class RSocketController { private AppProperties appProperties; "rsocket.message") ( public Mono<String> sendMessage(String input) { return Mono.just("RSocket服务端响应: " + input + " | " + appProperties.getRsocketMessage()); } }
WebSocket 服务端实现
WebSocket 服务端使用 Spring 提供的 TextWebSocketHandler
来处理消息。我们在收到客户端消息后,通过会话对象将响应发送回客户端。
package com.icoderoad.rwebsocket.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; import com.icoderoad.rwebsocket.config.AppProperties; public class WebSocketController extends TextWebSocketHandler { private AppProperties appProperties; protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { String clientMessage = message.getPayload(); String responseMessage = "WebSocket服务端响应: " + clientMessage + " | " + appProperties.getWebsocketMessage(); session.sendMessage(new TextMessage(responseMessage)); } }
WebSocket 配置类
使用 WebSocketConfigurer
来注册 WebSocket 的处理器,并允许跨域访问。
package com.icoderoad.rwebsocket.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; import com.icoderoad.rwebsocket.controller.WebSocketController; public class WebSocketConfig implements WebSocketConfigurer { private final WebSocketController webSocketController; public WebSocketConfig(WebSocketController webSocketController) { this.webSocketController = webSocketController; } public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(webSocketController, "/ws") .setAllowedOrigins("*"); } }
前端实现
前端使用 Thymeleaf 渲染,并通过 jQuery 与后端的 RSocket 和 WebSocket 进行交互。用户可以输入消息,通过点击按钮发送到后端,并接收后端的响应。
在 src/main/resources/templates
目录下创建 index.html
文件:
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>RSocket & WebSocket Demo</title> <!-- 引入 Bootstrap 样式 --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"> <!-- 引入 jQuery 和 Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script> <!-- 引入 RSocket 库 --> <script src="/js/rsocket-core.min.js"></script> <script src="/js/rsocket-websocket-client.min.js"></script> <style> .message-box { max-height: 300px; overflow-y: auto; border: 1px solid #dee2e6; padding: 10px; border-radius: 0.25rem; background-color: #f8f9fa; } .message-box p { margin-bottom: 0.5rem; } </style> </head> <body> <div class="container"> <h1 class="mt-5">RSocket & WebSocket Demo</h1> <!-- WebSocket 区域 --> <div class="mt-5"> <h3>WebSocket 消息</h3> <div class="input-group mb-3"> <input type="text" id="websocket-input" class="form-control" placeholder="输入 WebSocket 消息"> <button id="send-websocket" class="btn btn-primary">发送 WebSocket 消息</button> </div> <div id="websocket-messages" class="message-box"></div> </div> <!-- RSocket 区域 --> <div class="mt-5"> <h3>RSocket 消息</h3> <div class="input-group mb-3"> <input type="text" id="rsocket-input" class="form-control" placeholder="输入 RSocket 消息"> <button id="send-rsocket" class="btn btn-success">发送 RSocket 消息</button> </div> <div id="rsocket-messages" class="message-box"></div> </div> </div> <script> $(document).ready(function () { // WebSocket 连接 const ws = new WebSocket("ws://localhost:8080/ws"); ws.onmessage = function (event) { $("#websocket-messages").append(`<p>${event.data}</p>`); }; // 发送 WebSocket 消息 $("#send-websocket").click(function () { const message = $("#websocket-input").val(); if (message.trim()) { ws.send(message); $("#websocket-input").val(''); } }); const { RSocketClient } = window['rsocket-core']; const { default: RSocketWebSocketClient } = window['rsocket-websocket-client']; // RSocket 客户端创建和连接 async function createRSocketClient() { const transportOptions = { url: 'ws://localhost:7001/rsocket', }; const setupOptions = { keepAlive: 60000, lifetime: 180000, dataMimeType: 'application/json', metadataMimeType: 'message/x.rsocket.routing.v0', }; const transport = new RSocketWebSocketClient(transportOptions); const client = new RSocketClient({ setup: setupOptions, transport }); try { return await client.connect(); } catch (error) { console.error("RSocket 连接错误: ", error); throw error; } } // 处理 RSocket 消息 async function setupRSocket() { try { const socket = await createRSocketClient(); $("#send-rsocket").click(function () { const message = $("#rsocket-input").val(); if (message.trim()) { socket.requestResponse({ data: message, metadata: String.fromCharCode('rsocket.message'.length) + 'rsocket.message' }).subscribe({ onComplete: (response) => { $("#rsocket-messages").append(`<p>${response.data}</p>`); $("#rsocket-input").val(''); }, onError: (error) => { console.error("RSocket 错误: ", error); } }); } }); } catch (error) { console.error("启动 RSocket 客户端失败: ", error); } } setupRSocket(); }); </script> </body> </html>
总结
通过结合 RSocket 和 WebSocket,我们可以在 Spring Boot 3.3 中轻松实现高效的实时通信。RSocket 通过其多种通信模型和背压机制,为流式数据传输提供了强大的支持;WebSocket 则在全双工实时通信方面表现出色,适合需要即时数据更新的场景。通过本文的实例,读者可以在项目中灵活应用这两种技术,实现高效的消息交互。在前端,我们使用简单的输入框和按钮,演示了如何与服务器进行消息通信。这种方式不仅提升了用户体验,还能大幅提高系统的响应速度和处理效率。