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
MessageChannels, MessageHandlers
that Spring Integration uses,
and some POJO-method annotation mappings, Spring Integration can be directly involved in a
WebSocket flow, even without WebSocket adapters. For this purpose you can simply configure a
Spring Integration @MessagingGateway with appropriate annotations:
|
@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.<Transport>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 ServerWebSocketContainer implements WebSocketConfigurer
to register an internal IntegrationWebSocketContainer.IntegrationWebSocketHandler
as an Endpoint under the provided paths and other server WebSocket options (such as
HandshakeHandler or SockJS fallback) within the
ServletWebSocketHandlerRegistry for the target vendor WebSocket Container. This
registration is achieved with an infrastructural WebSocketIntegrationConfigurationInitializer
component, which does the same as the @EnableWebSocket annotation. This means that
using just @EnableIntegration (or any Spring Integration Namespace in the
application context)
you can omit the @EnableWebSocket declaration, because all WebSocket
Endpoints are detected by the Spring Integration infrastructure.
|
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 WebSocketListener can be registered in the
IntegrationWebSocketContainer.
|
For WebSocket sub-protocols, 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 WebSocketInboundChannelAdapter relies just only on the raw
PassThruSubProtocolHandler implementation, which simply converts the
WebSocketMessage to a Message.
|
The WebSocketInboundChannelAdapter accepts and sends to the underlying integration
flow only Messages with SimpMessageType.MESSAGE or an empty
simpMessageType header. All other Message types are handled
through the ApplicationEvents 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
AbstractBrokerMessageHandler reference, it is detected in the
Application Context.
|
For more configuration option see Section 31.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 6.2.2, “Header Enricher”).
For more configuration option 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=""
send-time-limit=""
send-buffer-size-limit="">
<int-websocket:sockjs client-library-url=""
stream-bytes-limit=""
session-cookie-needed=""
heartbeat-time=""
disconnect-delay=""
message-cache-size=""
websocket-enabled=""
scheduler=""
message-codec=""
transport-handlers="" /> (16) </int-websocket:server-container>
|
The component bean name. | |
|
A path (or comma-separated paths) that maps a particular request to a
| |
|
The | |
|
List of | |
|
See the same option on the | |
|
See the same option on the | |
|
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 |
<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 |