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
MessageChannel s, MessageHandler s
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 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
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 |