Spring Boot 中的 WebSocket:如何构建实时应用程序

介绍

WebSocket 利用单个长连接提供全双工通信通道。它是一个强大的工具,可以实现客户端和服务器之间的实时通信。在 Java 生态系统中,Spring 框架为基于 WebSocket 的通信提供良好的支持。在这篇文章中,我们将探讨如何使用 @EnableWebSocket 注释在 Spring 应用程序中开始使用 WebSocket。

为什么选择WebSocket

HTTP 的局限性

HTTP(超文本传输​协议)是一种请求-响应协议,自诞生以来一直是 Web 通信的支柱。然而,HTTP 有其局限性,尤其是在实时、双向通信方面。在传统的 用HTTP 请求的程序中,客户端发送请求,服务器发回响应。对于服务器需要在没有收到客户端请求的情况下,也要将数据推送到客户端的场景,http显然效率不高。人们开发了各种技术(例如长轮询和服务器发送事件)来规避此问题,但也有一些额外的局限性。

WebSocket 的诞生

引入 WebSocket 是为了克服这些限制并实现更具交互性的 Web 体验。它通过单个长连接在客户端和服务器之间建立全双工双向通信通道。这与 HTTP 不同,HTTP 中每次交互都需要一个新的请求-响应周期。 WebSocket 协议本身构建在 HTTP 之上,利用初始 HTTP 握手来建立 WebSocket 连接。

减少网络开销

WebSocket 的主要优点之一是它减少了网络开销。在 HTTP 中,每个请求都带有一组标头,其中包含有关请求的元数据。每次发出请求时都会发送这些标头,这对于偶尔的交互来说很好,但对于频繁的通信来说效率很低。使用 WebSocket,标头在初始握手期间仅发送一次,从而减少了通过网络传输的冗余数据量。

实时数据传输

WebSocket 在需要实时更新的场景中大放异彩。无论是聊天应用程序、实时体育比分更新还是股票市场仪表板,WebSocket 都可以在新数据可用时立即提供新数据。这在即使一秒钟的延迟都可能造成高昂代价的环境中至关重要。例如,在交易应用程序中,股票价格需要实时更新,以便交易者做出准确的决策。

可扩展性和资源利用率

在频繁更新的基于 HTTP 的应用程序中,服务器必须同时处理多个传入请求和传出响应,这会消耗更多的 CPU 和内存资源。使用 WebSocket,持久的单个连接可以更好地利用资源,因为服务器不必连续打开和关闭多个连接。这意味着可扩展性的提高,使您能够使用相同的硬件资源为更多的客户端提供服务。

双向通讯

WebSocket不仅允许服务器向客户端推送更新,还允许客户端与服务器实时通信。这种双向功能使 WebSocket 成为协作应用程序的绝佳选择。例如,在类似 在线 文档的应用程序中,多个用户可以编辑同一文档,并且一个用户的更改可以立即反映在其他人的界面上。

构建 Spring Boot 应用

Spring Boot 应用程序是任何基于 Spring 的项目的基础。让我们一步步了解构建websocket项目,创建到添加所需的依赖项。其中每个步骤对于在 Spring 中成功设置支持 WebSocket 的应用程序都至关重要。

添加maven依赖

下一步涉及将必要的依赖项添加到 Maven pom.xml 文件中。对于 WebSocket 支持,Spring 提供了

spring-boot-starter-websocket 依赖项。以下是将其包含在 Maven 配置中的方法:

xml 复制代码
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

这个包包含在 Spring 中开始使用 WebSocket的资源 ,无需额外配置单独的依赖项。它自动添加 WebSocket 库并提供自动配置

带有@EnableWebSocket的配置类

在 Spring 中,配置类充当设置各种功能的支柱。这些类用 @Configuration 进行注释,向 Spring 发出信号,表明它们定义了项目所需的 bean 和其他设置。使用 WebSocket 时,@EnableWebSocket 注释对于激活必要的组件并为实时通信奠定基础

@EnableWebSocket的作用

当您使用 @EnableWebSocket 注解配置类时,您实际上是在 Spring 应用程序中打开 WebSocket 功能。此注释注册 WebSocket 处理程序并设置处理 WebSocket 消息的基础。这是一种启用 WebSocket 功能的声明式方法,无需深入研究手动设置 WebSocket 服务器的具体细节。

实现WebSocketConfigurer

@EnableWebSocket 的配置类通常会实现 WebSocketConfigurer 接口。该接口为您提供了一个方法,registerWebSocketHandlers(

WebSocketHandlerRegistryregistry),您需要重写该方法。您可以在该方法中指定 URL 映射并将它们与其相应的 WebSocket 处理程序关联起来。

less 复制代码
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
  
  @Override
  public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(myHandler(), "/myHandler");
  }
  
}

添加自定义设置

WebSocketHandlerRegistry 允许您添加特定于 WebSocket 处理程序的自定义设置和配置。例如,您可以指定允许的来源来控制可以从哪些来源访问您的 WebSocket 服务器,如下所示:

typescript 复制代码
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
  registry.addHandler(myHandler(), "/myHandler")
          .setAllowedOrigins("http://example.com");
}

定义 Bean

还可以定义与 WebSocket 处理相关的 bean。您可以在此处添加其他自定义,例如为涉及向多个客户端广播消息的更复杂场景配置消息代理。

例如,您可以定义一个 WebSocketHandler bean:

typescript 复制代码
@Bean
public WebSocketHandler myHandler() {
  return new MyHandler();
}

在上面的代码片段中,定义了一个 WebSocketHandler 类型的 bean,Spring 将管理该 bean。该处理程序在 registerWebSocketHandlers 方法中注册。

实现 WebSocketHandler

下一个关键步骤就是实现 WebSocketHandler 接口。该接口是 Spring 中 WebSocket 消息处理的核心。它定义了应用程序将用于管理 WebSocket 会话和消息事件的核心方法。

WebSocketHandler接口

Spring 中的 WebSocketHandler 接口提供了各种方法,您可以重写这些方法来处理不同的 WebSocket 事件,例如打开连接、发送消息、接收消息和错误处理。

afterConnectionEstablished(WebSocketSession session):在建立新的 WebSocket 会话后调用此方法。

handleTextMessage(WebSocketSession session, TextMessage message):此方法处理传入的文本消息。

handleBinaryMessage(WebSocketSession session, BinaryMessage message):此方法处理二进制消息。

afterConnectionClosed(WebSocketSession session, CloseStatus status):在 WebSocket 会话关闭后调用此方法。

创建自定义处理程序

创建自定义 WebSocket 处理程序涉及实现 WebSocketHandler 接口并根据您的特定要求重写其方法。下面是自定义 WebSocketHandler 的框架示例

less 复制代码
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

public class MyHandler extends TextWebSocketHandler {

  @Override
  public void afterConnectionEstablished(WebSocketSession session) {

  }

  @Override
  protected void handleTextMessage(WebSocketSession session, TextMessage message) {

  }

  @Override
  public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {

  }
  
}

与业务逻辑集成

在重写的方法中,您可以与 Spring 应用程序的其他服务和组件集成。这可以是简单地广播接收到的消息,也可以是更复杂的操作,例如与数据库或外部 API 集成。例如:

typescript 复制代码
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
  String payload = message.getPayload();
  someService.processPayload(payload);
}

异常处理

连接可能会断开,并且可能会发送格式错误的消息。因此,强大的错误处理至关重要。您可以重写handleTransportError方法来处理此类情况:

typescript 复制代码
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) {
  // 处理异常
}

会话属性和用户标识

传递到这些方法中的 WebSocketSession 对象使您可以访问会话级属性、标头和其他有用的数据点。这对于识别用户和维护会话状态特别有帮助,特别是在需要身份验证和授权的应用程序中。

typescript 复制代码
public void afterConnectionEstablished(WebSocketSession session) {
  String username = session.getAttributes().get("username").toString();

}

线程安全和并发

注意多个线程可能同时访问 WebSocketHandler 的方法。如果您要维护处理程序中的任何状态,请确保它是线程安全的,以避免并发问题。

注册处理handler

注册 WebSocket 处理handler的过程是使 Spring Boot 应用程序能够处理 WebSocket 消息的最后一部分。可以通过 @EnableWebSocket 注解用了 WebSocket 支持。注册过程将您的自定义处理程序绑定到特定的 URL 端点,使客户端可以建立到该端点的 WebSocket 连接。

WebSocketHandlerRegistry

正如前面在配置类部分中提到的,WebSocketHandlerRegistry 是注册所有 WebSocket 处理程序的中心。通过这个注册表,Spring 可以识别您的自定义处理程序,并将其映射到应用程序中的特定路径。

如何注册handler

要注册您的处理程序,您通常会在传递到 registerWebSocketHandlers 方法的 WebSocketHandlerRegistry 对象上调用 addHandler 方法。 addHandler 的第一个参数是处理程序对象,第二个参数是可访问处理程序的 URL 映射。

typescript 复制代码
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
  registry.addHandler(myHandler(), "/ws");
}

自定义handler设置

addHandler 方法返回一个

WebSocketHandlerRegistration 对象,可以设置允许的来源来指定允许哪些网站连接到您的 WebSocket 端点

typescript 复制代码
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
  registry.addHandler(myHandler(), "/ws")
          .setAllowedOrigins("http://example.com");
}

拦截器

拦截器提供了一种在 WebSocket 握手之前和之后执行操作的方法,为您提供了实现身份验证或日志记录等功能的地方。要注册拦截器,可以使用

WebSocketHandlerRegistration 对象上的 addInterceptors 方法。

typescript 复制代码
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
  registry.addHandler(myHandler(), "/ws")
          .addInterceptors(new MyHandshakeInterceptor());
}

条件注册

有时,您可能需要根据运行时设置或配置文件有条件地注册处理程序。 Spring 的编程方法使您能够灵活地动态做出这些决策。

typescript 复制代码
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
  if (someCondition) {
    registry.addHandler(myHandler(), "/ws");
  }
}

多个handler

在更复杂的应用程序中,您可能有多个提供不同功能的 WebSocket 处理程序。注册多个处理程序很简单:

typescript 复制代码
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
  registry.addHandler(myChatHandler(), "/chat");
  registry.addHandler(myNotificationHandler(), "/notifications");
}

测试配置

单元测试

开始测试 WebSocket 配置的最简单方法是对各个组件执行单元测试。 Spring 强大的测试框架有助于轻松地对 WebSocket 处理程序进行单元测试。 下面是一个可用于测试 WebSocketHandler 的单元测试示例:

java 复制代码
@SpringBootTest
public class MyHandlerTest {

  @Autowired
  private MyHandler myHandler;

  @Test
  public void testHandleTextMessage() {
    WebSocketSession session = mock(WebSocketSession.class);
    TextMessage message = new TextMessage("Test message");
    myHandler.handleTextMessage(session, message);
    
  }
}

总结

Spring 框架通过 @EnableWebSocket 等易于使用的注释简化了 WebSocket 实现。这篇文章提供了如何在 Spring 中设置和配置 WebSocket 的快速指南,从初始设置到完整配置。 通过结合 Spring 和 WebSocket 的强大功能,您可以轻松创建高度交互的实时 Web 应用程序。只需几行配置,您就可以利用 WebSocket 来满足您的所有实时需求。

相关推荐
wellc31 分钟前
SpringBoot集成Flowable
java·spring boot·后端
Hui Baby1 小时前
springAi+MCP三种
java
hsjcjh1 小时前
【MySQL】C# 连接MySQL
java
敖正炀1 小时前
LinkedBlockingDeque详解
java
wangyadong3171 小时前
datagrip 链接mysql 报错
java
untE EADO1 小时前
Tomcat的server.xml配置详解
xml·java·tomcat
ictI CABL2 小时前
Tomcat 乱码问题彻底解决
java·tomcat
敖正炀2 小时前
DelayQueue 详解
java
敖正炀2 小时前
PriorityBlockingQueue 详解
java
shark22222222 小时前
Spring 的三种注入方式?
java·数据库·spring