Starting with version 4.1 Spring Integration has introduced WebSocket support.
It is based on architecture, infrastructure and API from the Spring Framework’s web-socket module.
Therefore, many of Spring WebSocket’s components (e.g.
SubProtocolHandler
or WebSocketClient
) and configuration options (e.g.
@EnableWebSocketMessageBroker
) can be reused within Spring Integration.
For more information, please, refer to the Spring Framework WebSocket Support chapter in the Spring Framework reference manual.
Note | |
---|---|
Since the Spring Framework WebSocket infrastructure is based on the Spring Messaging foundation and provides a basic Messaging framework based on the same |
@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/from a WebSocket at the same time, we can simply 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).
Hence most connection and WebSocketSession
registry options are the same on both sides.
That allows us to reuse many configuration items and infrastructure hooks to build WebSocket applications on the server side as well as on the client side:
//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 only from 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.
It must be supplied with a IntegrationWebSocketContainer
, and the adapter registers itself as a WebSocketListener
to handle incoming messages and WebSocketSession
events.
Note | |
---|---|
Only one |
For WebSocket _sub-protocol_s, 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 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
s with SimpMessageType.MESSAGE
or an empty simpMessageType
header.
All other Message
types are handled through the ApplicationEvent
s emitted from a SubProtocolHandler
implementation (e.g.
StompSubProtocolHandler
).
On the server side WebSocketInboundChannelAdapter
can be configured with the useBroker = true
option, if the @EnableWebSocketMessageBroker
configuration is present.
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, which match to the Broker destinations, are routed to the AbstractBrokerMessageHandler
, instead of to the outputChannel
of the WebSocketInboundChannelAdapter
.
If useBroker = false
and received message is of SimpMessageType.CONNECT
type, the WebSocketInboundChannelAdapter
sends SimpMessageType.CONNECT_ACK
message to the WebSocketSession
immediately without sending it to the channel.
Note | |
---|---|
Spring’s WebSocket Support allows the configuration of only one Broker Relay, hence we don’t require an |
For more configuration options see Section 35.5, “WebSockets Namespace Support”.
The WebSocketOutboundChannelAdapter
accepts Spring Integration messages from its MessageChannel
, determines the WebSocketSession
id
from the MessageHeaders
, retrieves the WebSocketSession
from the provided IntegrationWebSocketContainer
and delegates the conversion and sending WebSocketMessage
work to the appropriate SubProtocolHandler
from the provided SubProtocolHandlerRegistry
.
On the client side, the WebSocketSession
id
message header isn’t required, because ClientWebSocketContainer
deals only with a single connection and its WebSocketSession
respectively.
To use the STOMP sub-protocol, this adapter should be configured 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 7.2.2, “Header Enricher”).
For more configuration options see below.
Spring Integration WebSocket namespace includes several components described below. To include it in your configuration, simply provide 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>
<int-websocket:client-container>
<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 will start and the later it will stop.
The default is | |
A |
<int-websocket:server-container>
<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 | |
Configure one or more factories ( | |
See the same option on the | |
See the same option on the | |
Configure allowed Origin header values. Multiple origins may be specified as a comma-separated list. This check is mostly designed for browser clients. There is noting preventing other types of client to modify 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 (jsonp-polling, iframe-xhr-polling, iframe-eventsource and iframe-htmlfile) are disabled. As a consequence, IE6/IE7 are not supported and IE8/IE9 will only be supported without cookies. By default, all origins are allowed. | |
Transports with no native cross-domain communication (e.g.
"eventsource", "htmlfile") must get a simple page from the "foreign" domain in an invisible iframe so that code in the iframe can run from a domain local to the SockJS server.
Since the iframe needs to load the SockJS javascript client library, this property allows specifying where to load it from.
By default this is set to point to | |
Minimum number of bytes that can be send over a single HTTP streaming request before it will be closed.
Defaults to | |
The "cookie_needed" value in the response from the SockJs | |
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, i.e.
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 don’t support websockets.
Set this option to | |
The | |
The | |
List of | |
The option to disable automatic addition of CORS headers for SockJS requests.
The default value is |
<int-websocket:outbound-channel-adapter>
<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 the | |
Identifies the channel attached to this adapter. | |
The reference to the | |
Optional reference to a | |
List of | |
List of | |
Flag to indicate if 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.
Default to | |
The lifecycle phase within which this endpoint should start and stop.
The lower the value the earlier this endpoint will start and the later it will stop.
The default is |
<int-websocket:inbound-channel-adapter>
<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 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 may block.
For example, a | |
Fully qualified name of the java type for the target | |
Flag to indicate if this adapter will send | |
See the same option on the | |
See the same option on the |
Starting with version 4.3.13, the ClientStompEncoder
is provided as an extension of standard StompEncoder
for using on client side of the WebSocket Channel Adapters.
An instance of the ClientStompEncoder
must be injected into the StompSubProtocolHandler
for proper client side message preparation.
One of the problem of the default StompSubProtocolHandler
that it was designed for the server side, so it updates the SEND
stompCommand
header into MESSAGE
as it must be by the STOMP protocol from server side.
If client doesn’t send its messages in the proper SEND
web socket frame, some STOMP brokers won’t accept them.
The purpose of the ClientStompEncoder
, in this case, is to override stompCommand
header to the SEND
value before encoding the message to the byte[]
.