Starting with version 4.1, Spring Integration has WebSocket support.
It is based on the architecture, infrastructure, and API from the Spring Framework’s web-socket
module.
Therefore, many of Spring WebSocket’s components (such as SubProtocolHandler
or WebSocketClient
) and configuration options (such as @EnableWebSocketMessageBroker
) can be reused within Spring Integration.
For more information, see the Spring Framework WebSocket Support chapter in the Spring Framework reference manual.
You need to include this dependency into your project:
Maven.
<dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-websocket</artifactId> <version>5.1.2.RELEASE</version> </dependency>
Gradle.
compile "org.springframework.integration:spring-integration-websocket:5.1.2.RELEASE"
For server side, the org.springframework:spring-webmvc
dependency must be included explicitly.
The Spring Framework WebSocket infrastructure is based on the Spring messaging foundation and provides a basic messaging framework based on the same MessageChannel
implementations and MessageHandler
implementations that Spring Integration uses (and some POJO-method annotation mappings).
Consequently, Spring Integration can be directly involved in a WebSocket flow, even without WebSocket adapters.
For this purpose, you can configure a Spring Integration @MessagingGateway
with appropriate annotations, as the following example shows:
@MessagingGateway @Controller public interface WebSocketGateway { @MessageMapping("/greeting") @SendToUser("/queue/answer") @Gateway(requestChannel = "greetingChannel") String greeting(String payload); }
Since the WebSocket protocol is streaming by definition and we can send and receive messages to and from a WebSocket at the same time, we can deal with an appropriate WebSocketSession
, regardless of being on the client or server side.
To encapsulate the connection management and WebSocketSession
registry, the IntegrationWebSocketContainer
is provided with ClientWebSocketContainer
and ServerWebSocketContainer
implementations.
Thanks to the WebSocket API and its implementation in the Spring Framework (with many extensions), the same classes are used on the server side as well as the client side (from a Java perspective, of course).
Consequently, most connection and WebSocketSession
registry options are the same on both sides.
That lets us reuse many configuration items and infrastructure hooks to build WebSocket applications on the server side as well as on the client side.
The following example shows how components can serve both purposes:
//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(); }
The IntegrationWebSocketContainer
is designed to achieve bidirectional messaging and can be shared between inbound and outbound channel adapters (see below), can be referenced from only one of them when using one-way (sending or receiving) WebSocket messaging.
It can be used without any channel adapter, but, in this case, IntegrationWebSocketContainer
only plays a role as the WebSocketSession
registry.
Note | |
---|---|
The |
The WebSocketInboundChannelAdapter
implements the receiving part of WebSocketSession
interaction.
You must supply it with a IntegrationWebSocketContainer
, and the adapter registers itself as a WebSocketListener
to handle incoming messages and WebSocketSession
events.
Note | |
---|---|
Only one |
For WebSocket subprotocols, the WebSocketInboundChannelAdapter
can be configured with SubProtocolHandlerRegistry
as the second constructor argument.
The adapter delegates to the SubProtocolHandlerRegistry
to determine the appropriate SubProtocolHandler
for the accepted WebSocketSession
and to convert a WebSocketMessage
to a Message
according to the sub-protocol implementation.
Note | |
---|---|
By default, the |
The WebSocketInboundChannelAdapter
accepts and sends to the underlying integration flow only Message
instances that have SimpMessageType.MESSAGE
or an empty simpMessageType
header.
All other Message
types are handled through the ApplicationEvent
instances emitted from a SubProtocolHandler
implementation (such as
StompSubProtocolHandler
).
On the server side, if the @EnableWebSocketMessageBroker
configuration is present, you can configure WebSocketInboundChannelAdapter
with the useBroker = true
option.
In this case, all non-MESSAGE
Message
types are delegated to the provided AbstractBrokerMessageHandler
.
In addition, if the broker relay is configured with destination prefixes, those messages that match the Broker destinations are routed to the AbstractBrokerMessageHandler
instead of to the outputChannel
of the WebSocketInboundChannelAdapter
.
If useBroker = false
and the received message is of the SimpMessageType.CONNECT
type, the WebSocketInboundChannelAdapter
immediately sends a SimpMessageType.CONNECT_ACK
message to the WebSocketSession
without sending it to the channel.
Note | |
---|---|
Spring’s WebSocket Support allows the configuration of only one broker relay.
Consequently, we do not require an |
For more configuration options, see Section 36.4, “WebSockets Namespace Support”.
The WebSocketOutboundChannelAdapter
:
MessageChannel
WebSocketSession
id
from the MessageHeaders
WebSocketSession
from the provided IntegrationWebSocketContainer
WebSocketMessage
work to the appropriate SubProtocolHandler
from the provided SubProtocolHandlerRegistry
.
On the client side, the WebSocketSession
id
message header is not required, because ClientWebSocketContainer
deals only with a single connection and its WebSocketSession
respectively.
To use the STOMP subprotocol, you should configure this adapter with a StompSubProtocolHandler
.
Then you can send any STOMP message type to this adapter, using StompHeaderAccessor.create(StompCommand...)
and a MessageBuilder
, or just using a HeaderEnricher
(see Section 9.2.1, “Header Enricher”).
The rest of this chapter covers largely additional configuration options.
The Spring Integration WebSocket namespace includes several components described in the remainder of this chapter. To include it in your configuration, use the following namespace declaration in your application context configuration file:
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd http://www.springframework.org/schema/integration/websocket http://www.springframework.org/schema/integration/websocket/spring-integration-websocket.xsd"> ... </beans>
The following listing shows the attributes available for the <int-websocket:client-container>
element:
<int-websocket:client-container id="" client="" uri="" uri-variables="" origin="" send-time-limit="" send-buffer-size-limit="" auto-startup="" phase=""> <int-websocket:http-headers> <entry key="" value=""/> </int-websocket:http-headers> </int-websocket:client-container>
The component bean name. | |
The | |
The | |
Comma-separated values for the URI variable placeholders within the | |
The | |
The WebSocket session send timeout limit.
Defaults to | |
The WebSocket session send message size limit.
Defaults to | |
Boolean value indicating whether this endpoint should start automatically.
Defaults to | |
The lifecycle phase within which this endpoint should start and stop.
The lower the value, the earlier this endpoint starts and the later it stops.
The default is | |
A |
The following listing shows the attributes available for the <int-websocket:server-container>
element:
<int-websocket:server-container id="" path="" handshake-handler="" handshake-interceptors="" decorator-factories="" send-time-limit="" send-buffer-size-limit="" allowed-origins=""> <int-websocket:sockjs client-library-url="" stream-bytes-limit="" session-cookie-needed="" heartbeat-time="" disconnect-delay="" message-cache-size="" websocket-enabled="" scheduler="" (16) message-codec="" (17) transport-handlers="" (18) suppress-cors="true"="" /> (19) </int-websocket:server-container>
The component bean name. | |
A path (or comma-separated paths) that maps a particular request to a | |
The | |
List of | |
List of one or more factories ( | |
See the same option on the | |
See the same option on the | |
The allowed origin header values.
You can specify multiple origins as a comma-separated list.
This check is mostly designed for browser clients.
There is nothing preventing other types of client from modifying the origin header value.
When SockJS is enabled and allowed origins are restricted, transport types that do not use origin headers for cross-origin requests ( | |
Transports with no native cross-domain communication (such as | |
Minimum number of bytes that can be sent over a single HTTP streaming request before it is closed.
Defaults to | |
The | |
The amount of time (in milliseconds) when the server has not sent any messages and after which the server should
send a heartbeat frame to the client in order to keep the connection from breaking.
The default value is | |
The amount of time (in milliseconds) before a client is considered disconnected after not having a receiving connection (that is, an active connection over which the server can send data to the client).
The default value is | |
The number of server-to-client messages that a session can cache while waiting for the next HTTP polling request from the client.
The default size is | |
Some load balancers do not support WebSockets.
Set this option to | |
The | |
The | |
List of | |
Whether to disable automatic addition of CORS headers for SockJS requests.
The default value is |
The following listing shows the attributes available for the <int-websocket:outbound-channel-adapter>
element:
<int-websocket:outbound-channel-adapter id="" channel="" container="" default-protocol-handler="" protocol-handlers="" message-converters="" merge-with-default-converters="" auto-startup="" phase=""/>
The component bean name.
If you do not provide the | |
Identifies the channel attached to this adapter. | |
The reference to the | |
Optional reference to a | |
List of | |
List of | |
Boolean value indicating whether the default converters should be registered after any custom converters.
This flag is used only if | |
Boolean value indicating whether this endpoint should start automatically.
Defaults to | |
The lifecycle phase within which this endpoint should start and stop.
The lower the value, the earlier this endpoint starts and the later it stops.
The default is |
The following listing shows the attributes available for the <int-websocket:outbound-channel-adapter>
element:
<int-websocket:inbound-channel-adapter id="" channel="" error-channel="" container="" default-protocol-handler="" protocol-handlers="" message-converters="" merge-with-default-converters="" send-timeout="" payload-type="" use-broker="" auto-startup="" phase=""/>
The component bean name.
If you do not set the | |
Identifies the channel attached to this adapter. | |
The | |
See the same option on the | |
See the same option on the | |
See the same option on the | |
See the same option on the | |
See the same option on the | |
Maximum amount of time (in milliseconds) to wait when sending a message to the channel if the channel can block.
For example, a | |
Fully qualified name of the Java type for the target | |
Indicates whether this adapter sends | |
See the same option on the | |
See the same option on the |
Starting with version 4.3.13, Spring Integration provides ClientStompEncoder
(as an extension of the standard StompEncoder
) for use on the client side of WebSocket channel adapters.
For proper client side message preparation, you must inject an instance of the ClientStompEncoder
into the StompSubProtocolHandler
.
One problem with the default StompSubProtocolHandler
is that it was designed for the server side, so it updates the SEND
stompCommand
header into MESSAGE
(as required by the STOMP protocol for the server side).
If the client does not send its messages in the proper SEND
web socket frame, some STOMP brokers do not accept them.
The purpose of the ClientStompEncoder
, in this case, is to override the stompCommand
header and set it to the SEND
value before encoding the message to the byte[]
.