# WebSockets 支持
# WebSockets 支持
从版本 4.1 开始, Spring 集成有 WebSocket 支持。它基于 Spring 框架的web-socket
模块中的体系结构、基础设施和 API。因此, Spring WebSocket 的许多组件(例如SubProtocolHandler
或WebSocketClient
)和配置选项(例如@EnableWebSocketMessageBroker
)可以在 Spring 集成内重用。有关更多信息,请参见 Spring 框架参考手册中的Spring Framework WebSocket Support (opens new window)章节。
你需要在项目中包含此依赖项:
Maven
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-websocket</artifactId>
<version>5.5.9</version>
</dependency>
Gradle
compile "org.springframework.integration:spring-integration-websocket:5.5.9"
对于服务器端,必须显式地包含org.springframework:spring-webmvc
依赖项。
Spring 框架 WebSocket 基础设施是基于 Spring 消息传递基础并且提供了基于与 Spring 集成使用的相同的MessageChannel
实现和MessageHandler
实现(以及一些 POJO-method 注释映射)的基本消息传递框架。因此, Spring 集成可以直接参与到 WebSocket 流中,即使没有 WebSocket 适配器也是如此。为此,你可以使用适当的注释来配置 Spring 集成@MessagingGateway
,如下例所示:
@MessagingGateway
@Controller
public interface WebSocketGateway {
@MessageMapping("/greeting")
@SendToUser("/queue/answer")
@Gateway(requestChannel = "greetingChannel")
String greeting(String payload);
}
# 概述
由于 WebSocket 协议根据定义是流的并且我们可以同时向 WebSocket 发送和接收消息,因此我们可以处理适当的WebSocketSession
,而不管是在客户端还是服务器端。为了封装连接管理和WebSocketSession
注册中心,IntegrationWebSocketContainer
提供了ClientWebSocketContainer
和ServerWebSocketContainer
实现。由于WebSocket API (opens new window)及其在 Spring 框架中的实现(具有许多扩展),在服务器端和客户端都使用了相同的类(当然,从 Java 的角度来看)。因此,大多数连接和WebSocketSession
注册表选项在两边都是相同的。这使我们能够重用许多配置项和基础设施挂钩,以便在服务器端和客户端构建 WebSocket 应用程序。下面的示例展示了组件如何实现这两个目的:
//Client side
@Bean
public WebSocketClient webSocketClient() {
return new SockJsClient(Collections.singletonList(new WebSocketTransport(new JettyWebSocketClient())));
}
@Bean
public IntegrationWebSocketContainer clientWebSocketContainer() {
return new ClientWebSocketContainer(webSocketClient(), "ws://my.server.com/endpoint");
}
//Server side
@Bean
public IntegrationWebSocketContainer serverWebSocketContainer() {
return new ServerWebSocketContainer("/endpoint").withSockJs();
}
WebSocket 该被设计用于实现双向消息传递,并且可以在入站和出站通道适配器之间共享(见下文),在使用单向消息传递时可以仅从其中一个引用 WebSocket。它可以在没有任何通道适配器的情况下使用,但是,在这种情况下,IntegrationWebSocketContainer
仅作为WebSocketSession
注册中心发挥作用。
ServerWebSocketContainer 实现WebSocketConfigurer 将一个内部IntegrationWebSocketContainer.IntegrationWebSocketHandler 注册为Endpoint 。它在提供的 paths 下这样做和其他服务器 WebSocket 选项(例如HandshakeHandler 或SockJS fallback )内的ServletWebSocketHandlerRegistry 用于目标供应商 WebSocket 容器。该注册是通过一个基础设施 WebSocketIntegrationConfigurationInitializer 组件实现的,其执行与@EnableWebSocket 注释相同的操作。这意味着,通过使用 @EnableIntegration (或应用程序上下文中的任何 Spring 集成名称空间),你可以省略@EnableWebSocket 声明,因为 Spring 集成基础结构检测所有 WebSocket 端点。 |
---|
# WebSocket 入站通道适配器
WebSocketInboundChannelAdapter
实现了WebSocketSession
交互的接收部分。你必须为它提供IntegrationWebSocketContainer
,并且适配器将自身注册为WebSocketListener
以处理传入消息和WebSocketSession
事件。
只有一个WebSocketListener 可以在IntegrationWebSocketContainer 中注册。 |
---|
对于 WebSocket 子协议,WebSocketInboundChannelAdapter
可以配置SubProtocolHandlerRegistry
作为第二个构造函数参数。适配器委托给SubProtocolHandlerRegistry
,以确定适用于已接受的WebSocketSession
的SubProtocolHandler
,并根据子协议实现将WebSocketMessage
转换为Message
。
默认情况下,WebSocketInboundChannelAdapter 仅依赖于 RAWPassThruSubProtocolHandler 实现,该实现将WebSocketMessage 转换为Message 。 |
---|
WebSocketInboundChannelAdapter
只接受并发送到底层集成流Message
实例,这些实例具有SimpMessageType.MESSAGE
或空的simpMessageType
头。所有其他Message
类型都是通过ApplicationEvent
实现发出的SubProtocolHandler
实例来处理的(例如StompSubProtocolHandler
)。
在服务器端,如果存在@EnableWebSocketMessageBroker
配置,则可以使用useBroker = true
选项配置WebSocketInboundChannelAdapter
。在这种情况下,所有non-MESSAGE``Message
类型都被委托给所提供的AbstractBrokerMessageHandler
。此外,如果代理中继配置了目标前缀,那么那些匹配代理目标的消息将路由到AbstractBrokerMessageHandler
,而不是WebSocketInboundChannelAdapter
的outputChannel
。
如果useBroker = false
并且接收到的消息是SimpMessageType.CONNECT
类型的,则WebSocketInboundChannelAdapter
立即向SimpMessageType.CONNECT_ACK
消息发送WebSocketSession
,而不将其发送到信道。
Spring 的 WebSocket 支持只允许配置一个代理中继。 因此,我们不需要 AbstractBrokerMessageHandler 引用。它是在应用程序上下文中检测到的。 |
---|
有关更多配置选项,请参见WebSockets 名称空间支持。
# WebSocket 出站通道适配器
theWebSocketOutboundChannelAdapter
:
接受 Spring 来自其
MessageChannel
的集成消息从
MessageHeaders
中确定WebSocketSession``id
从提供的
IntegrationWebSocketContainer
检索WebSocketSession
从提供的
SubProtocolHandlerRegistry
将WebSocketMessage
工作的转换和发送委托给相应的SubProtocolHandler
。
在客户端,WebSocketSession``id
消息头不是必需的,因为ClientWebSocketContainer
仅处理单个连接及其WebSocketSession
分别。
要使用 STOMP 子协议,你应该使用StompSubProtocolHandler
配置此适配器。然后,你可以使用StompHeaderAccessor.create(StompCommand…)
和MessageBuilder
向此适配器发送任何 Stomp 消息类型,或者只使用HeaderEnricher
(参见页眉 Enricher)。
本章的其余部分主要介绍了附加的配置选项。
# WebSockets 名称空间支持
Spring 集成 WebSocket 命名空间包括在本章的其余部分中描述的几个组件。要将其包含在配置中,请在应用程序上下文配置文件中使用以下名称空间声明:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-websocket="http://www.springframework.org/schema/integration/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/websocket
https://www.springframework.org/schema/integration/websocket/spring-integration-websocket.xsd">
...
</beans>
# <int-websocket:client-container>
属性
下面的清单显示了<int-websocket:client-container>
元素可用的属性:
<int-websocket:client-container
id="" (1)
client="" (2)
uri="" (3)
uri-variables="" (4)
origin="" (5)
send-time-limit="" (6)
send-buffer-size-limit="" (7)
auto-startup="" (8)
phase=""> (9)
<int-websocket:http-headers>
<entry key="" value=""/>
</int-websocket:http-headers> (10)
</int-websocket:client-container>
1 | 组件 Bean 名称。 |
---|---|
2 | 参考文献WebSocketClient Bean。 |
3 | 将uri 或uriTemplate 发送到目标 WebSocket 服务。如果将其用作带有 URI 变量占位符的 uriTemplate ,则需要uri-variables 属性。 |
4 | 属性值内的 URI 变量占位符的逗号分隔的值。 这些值根据它们在 uri 中的顺序被替换到占位符中。参见[ UriComponents.expand(Object…uriVariableValues) (https://DOCS. Spring.io/ Spring//DOCS/current/javadoc-api/org/SpringFramework/web/util/utilComponents.html expand-uribot)。 |
5 | Origin 握手 HTTP 标头值。 |
6 | WebSocket 会话“发送”超时限制。 默认为 10000 。 |
7 | WebSocket 会话“发送”消息大小限制。 默认为 524288 。 |
8 | 布尔值,表示此端点是否应自动启动。 默认为 false ,假设此容器是从WebSocket inbound adapter启动的。 |
9 | 这个端点应该在其中开始和停止的生命周期阶段。 值越低,这个端点开始得越早,停止得越晚。 默认值是 Integer.MAX_VALUE 。值可以是负数。 参见[ SmartLifeCycle (https:/DOCS. Spring.io/ Spring//DOCS/current/javadoc-api/org/api/context/smartlifycle.html)。 |
10 | aMap ofHttpHeaders 用于握手请求。 |
# <int-websocket:server-container>
属性
下面的清单显示了<int-websocket:server-container>
元素可用的属性:
<int-websocket:server-container
id="" (1)
path="" (2)
handshake-handler="" (3)
handshake-interceptors="" (4)
decorator-factories="" (5)
send-time-limit="" (6)
send-buffer-size-limit="" (7)
allowed-origins=""> (8)
<int-websocket:sockjs
client-library-url="" (9)
stream-bytes-limit="" (10)
session-cookie-needed="" (11)
heartbeat-time="" (12)
disconnect-delay="" (13)
message-cache-size="" (14)
websocket-enabled="" (15)
scheduler="" (16)
message-codec="" (17)
transport-handlers="" (18)
suppress-cors="true"="" /> (19)
</int-websocket:server-container>
1 | 组件 Bean 名称。 |
---|---|
2 | 一种将特定请求映射到WebSocketHandler 的路径(或以逗号分隔的路径)。支持精确的路径映射 URI(例如 /myPath )和 Ant 样式的路径模式(例如/myPath/** )。 |
3 | HandshakeHandler Bean 引用.默认为 DefaultHandshakeHandler 。 |
4 | 参考文献列表HandshakeInterceptor Bean。 |
5 | 用于修饰用于处理 WebSocket 消息的处理程序的一个或多个工厂的列表(WebSocketHandlerDecoratorFactory )。这对于某些高级用例(例如,以允许 Spring 安全性在相应的 HTTP会话过期时强制关闭 WebSocket 会话。有关更多信息,请参见。 |
6 | 请参阅[<int-websocket:client-container> ](# WebSocket-client-container-attributes)上的相同选项。 |
7 | 请参阅[<int-websocket:client-container> ](# WebSocket-client-container-attributes)上的相同选项。 |
8 | 允许的源头值。 你可以将多个源代码指定为逗号分隔的列表。 此检查主要是为浏览器客户端设计的。 没有什么可以阻止其他类型的客户端修改源头值。 当启用 Sockjs 并且限制允许的源代码时,不使用起源头来处理跨起源请求( jsonp-polling ,iframe-xhr-polling ,iframe-eventsource ,和iframe-htmlfile )的传输类型将被禁用。因此,不支持 IE6 和 IE7,并且只支持 IE8 和 IE9 而不支持 cookie。默认情况下,所有起源都是允许的。 |
9 | 没有本机跨域通信的传输(例如eventsource 和htmlfile )必须在不可见的 iframe 中从“foreign”域获得一个简单的页面,以便 IFRAME 中的代码可以从本地域运行到 Sockjs 服务器。由于 IFRAME 需要加载 Sockjs JavaScript 客户库,因此该属性允许你指定加载它的位置。 默认情况下,它指向 [https://d1fxtkz8shb9d2.cloudfront.net/sockjs-0.3.4.min.js](https://d1fxtkz8shb9d2.cloudfront.net/sockjs-0.3.4.min.js) 。,但是,,还可以将它设置为指向应用程序提供的 URL。 注意,可以指定一个相对 URL,在这种情况下,URL 必须与 IFRAME URL 相对。 ,例如,假设一个 Sockjs 端点映射到 /sockjs ,并且得到的 iFrame URL 是/sockjs/iframe.html ,那么相对 URL 必须以“.././”开头,才能遍历到 Sockjs 映射上方的位置。对于基于前缀的 Servlet 映射,你可能需要再遍历一次。 |
10 | 在关闭单个 HTTP 流请求之前,可以通过该请求发送的最小字节数。 默认为 128K (即 128*1024 或 131072 字节)。 |
11 | 来自 Sockjs 的响应中的cookie_needed 值/info Endpoint.此属性指示应用程序是否需要 JSESSIONID cookie 才能正常工作(例如,用于负载平衡或在 Java Servlet 容器中使用 HTTP会话)。 |
12 | 当服务器没有发送任何消息时的时间量(以毫秒为单位),在此之后服务器应该 向客户端发送心跳帧,以防止连接中断。 默认值为 25,000 (25 秒)。 |
13 | 客户机在没有接收连接(即服务器可以在其上向客户机发送数据的活动连接)之后被认为断开连接之前的时间量(以毫秒为单位)。 默认值为 5000 。 |
14 | 会话在等待来自客户端的下一个 HTTP 轮询请求时可以缓存的服务器到客户端消息的数量。 默认大小为 100 。 |
15 | 有些负载均衡器不支持 WebSockets。 将此选项设置为 false ,以禁用服务器端的 WebSocket 传输。默认值为 true 。 |
16 | TaskScheduler Bean 引用。如果不提供值,将创建一个新的 ThreadPoolTaskScheduler 实例。此调度程序实例用于调度心跳消息。 |
17 | 该 Bean 引用用于编码和解码 Sockjs 消息。默认情况下,使用,这要求在 Classpath 上存在 Jackson 库。 |
18 | 参考文献列表TransportHandler Bean。 |
19 | 是否禁用自动添加 SOCKJS 请求的 CORS 头。 默认值为 false 。 |
# <int-websocket:outbound-channel-adapter>
属性
下面的清单显示了<int-websocket:outbound-channel-adapter>
元素可用的属性:
<int-websocket:outbound-channel-adapter
id="" (1)
channel="" (2)
container="" (3)
default-protocol-handler="" (4)
protocol-handlers="" (5)
message-converters="" (6)
merge-with-default-converters="" (7)
auto-startup="" (8)
phase=""/> (9)
1 | 组件 Bean name. 如果不提供 channel 属性,则在应用程序上下文中创建并注册一个DirectChannel ,并将该id 属性作为 Bean 名称。在这种情况下,端点以 Bean 名称 id 加上.adapter 注册。而 MessageHandler 则以 Bean 别名id 加上.handler 注册。 |
---|---|
2 | 标识连接到此适配器的通道。 |
3 | 对IntegrationWebSocketContainer Bean 的引用,它封装了低级连接和WebSocketSession 处理操作。需要。 |
4 | 对SubProtocolHandler 实例的可选引用。当客户端未请求子协议或它是单个协议处理程序时使用。 如果未提供此引用或 protocol-handlers 列表,则默认使用PassThruSubProtocolHandler 。 |
5 | 该通道适配器的SubProtocolHandler Bean 引用列表。如果只提供单个 Bean 引用而不提供 default-protocol-handler ,则该单个SubProtocolHandler 用作default-protocol-handler 。如果不设置此属性或 default-protocol-handler ,默认情况下使用PassThruSubProtocolHandler 。 |
6 | 此通道适配器的MessageConverter Bean 引用列表。 |
7 | 布尔值,表示是否应在任何自定义转换器之后注册默认转换器。 只有在提供 message-converters 时才使用此标志。否则,将注册所有默认转换器。 默认为 false 。默认转换器(按顺序排列): StringMessageConverter ,ByteArrayMessageConverter ,和(如果 Jackson 库存在于 Classpath 上)。 |
8 | 布尔值,表示此端点是否应自动启动。 默认为 true 。 |
9 | 这个端点应该在其中开始和停止的生命周期阶段。 值越低,这个端点开始得越早,停止得越晚。 默认值是 Integer.MIN_VALUE 。值可以是负数。 参见[ SmartLifeCycle (https:/DOCS. Spring.io/ Spring/DOCS/current/javadoc-apf/org/api/context/smartlifycle.html)。 |
# <int-websocket:inbound-channel-adapter>
属性
下面的清单显示了<int-websocket:outbound-channel-adapter>
元素可用的属性:
<int-websocket:inbound-channel-adapter
id="" (1)
channel="" (2)
error-channel="" (3)
container="" (4)
default-protocol-handler="" (5)
protocol-handlers="" (6)
message-converters="" (7)
merge-with-default-converters="" (8)
send-timeout="" (9)
payload-type="" (10)
use-broker="" (11)
auto-startup="" (12)
phase=""/> (13)
1 | 组件 Bean name. 如果不设置 channel 属性,则在应用程序上下文中创建并注册一个DirectChannel ,并将该id 属性作为 Bean 名称。在本例中,端点以 Bean 名称 id 加上.adapter 进行注册。 |
---|---|
2 | 标识连接到此适配器的通道。 |
3 | 应该发送ErrorMessage 实例的MessageChannel Bean 引用。 |
4 | 请参阅[<int-websocket:outbound-channel-adapter> ](# WebSocket-出站-通道-适配器-属性)上的相同选项。 |
5 | 请参阅[<int-websocket:outbound-channel-adapter> ](# WebSocket-出站-通道-适配器-属性)上的相同选项。 |
6 | 请参阅[<int-websocket:outbound-channel-adapter> ](# WebSocket-出站-通道-适配器-属性)上的相同选项。 |
7 | 请参阅[<int-websocket:outbound-channel-adapter> ](# WebSocket-出站-通道-适配器-属性)上的相同选项。 |
8 | 请参阅[<int-websocket:outbound-channel-adapter> ](# WebSocket-出站-通道-适配器-属性)上的相同选项。 |
9 | 如果信道可以阻塞,则在向信道发送消息时等待的最大时间量(以毫秒为单位)。 例如,如果已达到其最大容量,则 QueueChannel 可以阻塞直到可用空间。 |
10 | 用于从传入的WebSocketMessage 转换为目标payload 的完全限定的 Java 类型名称。默认为 java.lang.String 。 |
11 | 指示此适配器是否从应用程序上下文向AbstractBrokerMessageHandler 发送带有代理目的地的AbstractBrokerMessageHandler 实例和消息。当此属性为 true 时,需要Broker Relay 配置。此属性仅在服务器端使用。 在客户端,它被忽略。 默认为 false 。 |
12 | 请参阅[<int-websocket:outbound-channel-adapter> ](# WebSocket-出站-通道-适配器-属性)上的相同选项。 |
13 | 参见[<int-websocket:outbound-channel-adapter> ](# WebSocket-出站-通道-适配器-属性)上的相同选项。 |
# 使用ClientStompEncoder
从版本 4.3.13 开始, Spring 集成提供了ClientStompEncoder
(作为标准StompEncoder
的扩展),用于在 WebSocket 通道适配器的客户端上使用。为了进行正确的客户端消息准备,你必须将ClientStompEncoder
的一个实例注入StompSubProtocolHandler
中。默认StompSubProtocolHandler
的一个问题是,它是为服务器端设计的,因此它将SEND``stompCommand
报头更新为MESSAGE
(根据服务器端的 stomp 协议的要求)。如果客户机没有在适当的SEND
Web 套接字框架中发送消息,则某些 STOMP 代理不接受它们。在这种情况下,ClientStompEncoder
的目的是覆盖stompCommand
头并将其设置为SEND
值,然后将消息编码为byte[]
。
# 动态 WebSocket 端点注册
从版本 5.5 开始, WebSocket 服务器端点(基于ServerWebSocketContainer
的通道适配器)现在可以在运行时注册(并删除)-映射的paths
aServerWebSocketContainer
通过HandlerMapping
公开到DispatcherServlet
中,并可供 WebSocket 客户端访问。动态和运行时集成流支持有助于以透明的方式注册这些端点:
@Autowired
IntegrationFlowContext integrationFlowContext;
@Autowired
HandshakeHandler handshakeHandler;
...
ServerWebSocketContainer serverWebSocketContainer =
new ServerWebSocketContainer("/dynamic")
.setHandshakeHandler(this.handshakeHandler);
WebSocketInboundChannelAdapter webSocketInboundChannelAdapter =
new WebSocketInboundChannelAdapter(serverWebSocketContainer);
QueueChannel dynamicRequestsChannel = new QueueChannel();
IntegrationFlow serverFlow =
IntegrationFlows.from(webSocketInboundChannelAdapter)
.channel(dynamicRequestsChannel)
.get();
IntegrationFlowContext.IntegrationFlowRegistration dynamicServerFlow =
this.integrationFlowContext.registration(serverFlow)
.addBean(serverWebSocketContainer)
.register();
...
dynamicServerFlow.destroy();
在动态流注册中调用.addBean(serverWebSocketContainer) 将ServerWebSocketContainer 的实例添加到ApplicationContext 中以进行端点注册是很重要的,当动态流注册被破坏时,相关的 ServerWebSocketContainer 实例也被破坏,以及相应的端点注册也被破坏,包括 URL 路径映射。 |
---|
动态 WebSocket 端点只能通过 Spring 集成机制进行注册:当使用常规 Spring 时, Spring 集成配置退出,并且不注册用于动态端点的基础设施。 |
---|
← WebFlux 支持 Web 服务支持 →