Add WebSocket reference documentation
Update reference documentation with a new section for Spring 4's WebSocket support.
This commit is contained in:
		
							parent
							
								
									0a52c86559
								
							
						
					
					
						commit
						01a78bbbac
					
				| 
						 | 
				
			
			@ -184,7 +184,7 @@ old Java objects)__.
 | 
			
		|||
 | 
			
		||||
[[overview-web]]
 | 
			
		||||
==== Web
 | 
			
		||||
The __Web__ layer consists of the Web, Web-Servlet, Web-Struts, and Web-Portlet modules.
 | 
			
		||||
The __Web__ layer consists of the Web, Web-Servlet, WebSocket and Web-Portlet modules.
 | 
			
		||||
 | 
			
		||||
Spring's __Web__ module provides basic web-oriented integration features such as
 | 
			
		||||
multipart file-upload functionality and the initialization of the IoC container using
 | 
			
		||||
| 
						 | 
				
			
			@ -744,6 +744,7 @@ the exact version and feature set of the container.
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[spring-core]]
 | 
			
		||||
= Core Technologies
 | 
			
		||||
[partintro]
 | 
			
		||||
| 
						 | 
				
			
			@ -27543,20 +27544,25 @@ within Web services.
 | 
			
		|||
= The Web
 | 
			
		||||
[partintro]
 | 
			
		||||
--
 | 
			
		||||
This part of the reference documentation covers the Spring Framework's support for the
 | 
			
		||||
presentation tier (and specifically web-based presentation tiers).
 | 
			
		||||
This part of the reference documentation covers Spring Framework's support for the
 | 
			
		||||
presentation tier (and specifically web-based presentation tiers) including support
 | 
			
		||||
for WebSocket-style messaging in web applications.
 | 
			
		||||
 | 
			
		||||
The Spring Framework's own web framework, <<mvc,Spring Web MVC>>, is covered in the
 | 
			
		||||
first couple of chapters. Subsequent chapters are concerned with the Spring Framework's
 | 
			
		||||
Spring Framework's own web framework, <<mvc,Spring Web MVC>>, is covered in the
 | 
			
		||||
first couple of chapters. Subsequent chapters are concerned with Spring Framework's
 | 
			
		||||
integration with other web technologies, such as <<struts,Struts>> <<jsf,JSF>> and
 | 
			
		||||
others.
 | 
			
		||||
 | 
			
		||||
Following that is coverage of Spring's MVC <<portlet,portlet framework>>.
 | 
			
		||||
Following that is coverage of Spring Framework's MVC <<portlet,portlet framework>>.
 | 
			
		||||
 | 
			
		||||
The section then concludes with comprehensive coverage of the Spring Framework
 | 
			
		||||
<<websocket>> (including <<websocket-stomp>>).
 | 
			
		||||
 | 
			
		||||
* <<mvc>>
 | 
			
		||||
* <<view>>
 | 
			
		||||
* <<web-integration>>
 | 
			
		||||
* <<portlet>>
 | 
			
		||||
* <<websocket>>
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36090,6 +36096,739 @@ Some older portals have been known to corrupt the definition of the
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket]]
 | 
			
		||||
== WebSocket Support
 | 
			
		||||
This part of the reference documentation covers Spring Framework's support for
 | 
			
		||||
WebSocket-style messaging in web applications including use of STOMP as an
 | 
			
		||||
application level WebSocket sub-protocol.
 | 
			
		||||
 | 
			
		||||
<<websocket-intro>> establishes a frame of mind in which to think about
 | 
			
		||||
WebSocket covering adoption challenges, design considerations, and thoughts on
 | 
			
		||||
it is a good fit.
 | 
			
		||||
 | 
			
		||||
<<websocket-server>> reviews the Spring WebSocket API on the
 | 
			
		||||
server-side while <<websocket-fallback>> explains the SockJS protocol and shows
 | 
			
		||||
how to configure and use it.
 | 
			
		||||
 | 
			
		||||
<<websocket-stomp-overview>> introduces the STOMP messaging protocol.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-intro]]
 | 
			
		||||
=== Introduction
 | 
			
		||||
The WebSocket protocol http://tools.ietf.org/html/rfc6455[RFC 6455] defines an important
 | 
			
		||||
new capability for web applications: full-duplex, two-way communication between client
 | 
			
		||||
and server. It is an exciting new capability on the heels of a long history of
 | 
			
		||||
techniques to make the web more interactive including Java applets, XMLHttpRequest,
 | 
			
		||||
Adobe Flash, ActiveXObject, various Comet techniques, server-sent events, and others.
 | 
			
		||||
 | 
			
		||||
A proper introduction of the WebSocket protocol is beyond the scope of this
 | 
			
		||||
document. At a minimum however it's important to understand that HTTP is used only for
 | 
			
		||||
the initial handshake, which relies on a mechanism built into HTTP to request
 | 
			
		||||
a protocol upgrade (or in this case a protocol switch) to which the server can respond with
 | 
			
		||||
HTTP status 101 (switching protocols) if it agrees. Assuming the handshake succeeds
 | 
			
		||||
the TCP socket underlying the HTTP upgrade request remains open and both client and
 | 
			
		||||
server can use it to send messages to each other.
 | 
			
		||||
 | 
			
		||||
Spring Framework 4 includes a new `spring-websocket` module with comprehensive
 | 
			
		||||
WebSocket support. It is compatible with the Java WebSocket API standard (JSR-356)
 | 
			
		||||
and also provides additional value-add as explained in the rest of the introduction.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-into-fallback-options]]
 | 
			
		||||
==== Fallback Options
 | 
			
		||||
An important challenge to adoption is the lack of support for WebSocket in some
 | 
			
		||||
browsers. Notably the first Internet Explorer version to support WebSocket is
 | 
			
		||||
version 10 (see http://caniuse.com/websockets for support by browser versions).
 | 
			
		||||
Furthermore some restrictive proxies
 | 
			
		||||
may be configured in ways that either preclude the attempt to do HTTP upgrade
 | 
			
		||||
or otherwise break connection after some time because it has remained opened
 | 
			
		||||
for too long. For a good overview on this topic see
 | 
			
		||||
http://www.infoq.com/articles/Web-Sockets-Proxy-Servers[this article].
 | 
			
		||||
 | 
			
		||||
Therefore to build a WebSocket application today, fallback options are required
 | 
			
		||||
to simulate the WebSocket API where necessary.
 | 
			
		||||
Spring Framework provides such transparent fallback
 | 
			
		||||
options based on the https://github.com/sockjs/sockjs-protocol[SockJS protocol].
 | 
			
		||||
These options can be enabled through configuration and do not require
 | 
			
		||||
modifying the application otherwise.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-intro-architecture]]
 | 
			
		||||
==== Messaging Architecture
 | 
			
		||||
Aside from short-to-midterm adoption challenges using WebSocket
 | 
			
		||||
brings up important design considerations that are important to recognize
 | 
			
		||||
early on especially in contrast to what we know about building web applications today.
 | 
			
		||||
 | 
			
		||||
Today REST is a widely accepted, understood, and supported
 | 
			
		||||
architecture for building web applications. It is an architecture that relies
 | 
			
		||||
on having many URLs (nouns), a handful of HTTP methods (verbs), and
 | 
			
		||||
other principles such as using hypermedia (links), remaining stateless, etc.
 | 
			
		||||
 | 
			
		||||
By contrast a WebSocket application may use a single URL only for the
 | 
			
		||||
initial HTTP handshake. All messages thereafter share and flow on the
 | 
			
		||||
same TCP connection. This points to an entirely different, asynchronous,
 | 
			
		||||
event-driven, messaging architecture. One that is much closer
 | 
			
		||||
to traditional messaging applications (e.g. JMS, AMQP).
 | 
			
		||||
 | 
			
		||||
Spring Framework 4 includes a new `spring-messaging` module with key
 | 
			
		||||
abstractions from the
 | 
			
		||||
http://projects.spring.io/spring-integration/[Spring Integration] project
 | 
			
		||||
such as `Message`, `MessageChannel`, `MessageHandler` and others that can serve as
 | 
			
		||||
a foundation for such a messaging architecture. The module also includes a
 | 
			
		||||
set of annotations for mapping messages to methods similar to the Spring MVC
 | 
			
		||||
annotation based programming model.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-intro-sub-protocol]]
 | 
			
		||||
==== Sub-Protocol Support
 | 
			
		||||
WebSocket does imply a messaging architecture but does not mandate the
 | 
			
		||||
use of any specific messaging protocol. It is a very thin layer over TCP
 | 
			
		||||
that transforms a stream of bytes into a stream of messages
 | 
			
		||||
(either text or binary) and not much more. It is up to applications
 | 
			
		||||
to interpret the meaning of a message.
 | 
			
		||||
 | 
			
		||||
Unlike HTTP which is an application-level protocol, in the WebSocket protocol
 | 
			
		||||
there is simply not enough information in an incoming message for a framework
 | 
			
		||||
or container to know how to route it or process it. Therefore WebSocket is arguably
 | 
			
		||||
too low level for anything but a very trivial application. It can be done but
 | 
			
		||||
it will likely lead to creating a framework on top. This is comparable to how
 | 
			
		||||
most web applications today are written using a web framework rather than the
 | 
			
		||||
Servlet API alone.
 | 
			
		||||
 | 
			
		||||
For this reason the WebSocket RFC defines the use of
 | 
			
		||||
http://tools.ietf.org/html/rfc6455#section-1.9[sub-protocols].
 | 
			
		||||
During the handshake client and server can use the header
 | 
			
		||||
`Sec-WebSocket-Protocol` to agree on a sub-protocol, i.e. a higher, application-level
 | 
			
		||||
protocol to use. The use of a sub-protocol is not required but
 | 
			
		||||
even if not used, applications will still need to choose a message
 | 
			
		||||
format that both client and server can understand. That format can be custom,
 | 
			
		||||
framework-specific, or a standard messaging protocol.
 | 
			
		||||
 | 
			
		||||
Spring Framework provides support for using
 | 
			
		||||
http://stomp.github.io/stomp-specification-1.2.html#Abstract[STOMP] -- a simple, messaging protocol
 | 
			
		||||
originally created for use in scripting languages with frames inspired
 | 
			
		||||
by HTTP. STOMP is widely support and well suited for use over
 | 
			
		||||
WebSocket and over the web.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-intro-when-to-use]]
 | 
			
		||||
==== When To Use WebSocket?
 | 
			
		||||
With all design considerations surrounding the use of WebSocket, it is
 | 
			
		||||
reasonable to ask when is it appropriate to use?
 | 
			
		||||
 | 
			
		||||
The best fit for WebSocket is in web applications where client and
 | 
			
		||||
server need to exchange events at high frequency and at low latency. Prime
 | 
			
		||||
candidates include but are not limited to applications in finance, games,
 | 
			
		||||
collaboration, and others. Such applications are both very sensitive to time
 | 
			
		||||
delays and also need to exchange a wide variety of messages at high
 | 
			
		||||
frequency.
 | 
			
		||||
 | 
			
		||||
For other application types however this may not be the case.
 | 
			
		||||
For example a news or social feed that shows breaking news as they become
 | 
			
		||||
available may be perfectly okay with simple polling once every few minutes.
 | 
			
		||||
Here latency is important but it is not as crucial if the news takes a
 | 
			
		||||
few minutes to appear.
 | 
			
		||||
 | 
			
		||||
Even in cases where latency is crucial, if the volume of messages is
 | 
			
		||||
relatively low (e.g. monitoring network failures) the use of
 | 
			
		||||
http://spring.io/blog/2012/05/08/spring-mvc-3-2-preview-techniques-for-real-time-updates[long polling]
 | 
			
		||||
should be considered as a relatively simple alternative that
 | 
			
		||||
works reliably and is comparable by efficiency (again assuming the volume of
 | 
			
		||||
messages is relatively low).
 | 
			
		||||
 | 
			
		||||
It is the combination of both low latency and high frequency of messages that can make
 | 
			
		||||
the use of the WebSocket protocol critical. Even in such applications
 | 
			
		||||
the choice remains whether all client-server
 | 
			
		||||
communication should be done through WebSocket messages as opposed to using
 | 
			
		||||
HTTP and REST? The answer is going to vary by application, however it is likely
 | 
			
		||||
that some functionality may be exposed over both WebSocket and as a REST API in
 | 
			
		||||
order to provide clients with alternatives. Furthermore a REST API call may need
 | 
			
		||||
to broadcast a message to interested clients connected via WebSocket.
 | 
			
		||||
 | 
			
		||||
Spring Framework allows `@Controller` classes to have both
 | 
			
		||||
HTTP request handling and WebSocket message handling methods.
 | 
			
		||||
Furthermore, a Spring MVC request handling method, or any application
 | 
			
		||||
method for that matter, can easily broadcast a message to all interested
 | 
			
		||||
WebSocket clients or to a specific user.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-server]]
 | 
			
		||||
=== WebSocket Server
 | 
			
		||||
The Spring Framework provides a WebSocket API designed to adapt to various WebSocket engines.
 | 
			
		||||
For example it runs on JSR-356 runtimes such as Tomcat (7.0.47+) and Glassfish (4.0+) but
 | 
			
		||||
can also adapt to other WebSocket runtimes such as the Jetty (9.0+) native WebSocket support.
 | 
			
		||||
 | 
			
		||||
[NOTE]
 | 
			
		||||
====
 | 
			
		||||
As explained in the <<websocket-intro-sub-protocol,introduction>> direct use of a
 | 
			
		||||
WebSocket API is too low level for applications -- until assumptions are made about the
 | 
			
		||||
format of a message there is little a framework can do to interpret messages or route
 | 
			
		||||
them via annotations. This is why applications should consider using a sub-protocol
 | 
			
		||||
and Spring's <<websocket-stomp,STOMP over WebSocket>> support.
 | 
			
		||||
 | 
			
		||||
When using a higher level protocol, the details of the WebSocket API become less
 | 
			
		||||
relevant much like the details of TCP communication are not exposed to applications
 | 
			
		||||
when using HTTP. Nevertheless this section covers the details of using WebSocket
 | 
			
		||||
directly.
 | 
			
		||||
====
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-server-handler]]
 | 
			
		||||
==== Create and Configure a WebSocketHandler
 | 
			
		||||
Creating a WebSocket server is as simple as implementing `WebSocketHandler` or more
 | 
			
		||||
likely extending either `TextWebSocketHandler` or `BinaryWebSocketHandler`:
 | 
			
		||||
 | 
			
		||||
[source,java,indent=0]
 | 
			
		||||
[subs="verbatim,quotes"]
 | 
			
		||||
----
 | 
			
		||||
	import org.springframework.web.socket.WebSocketHandler;
 | 
			
		||||
	import org.springframework.web.socket.WebSocketSession;
 | 
			
		||||
	import org.springframework.web.socket.TextMessage;
 | 
			
		||||
 | 
			
		||||
	public class MyHandler extends TextWebSocketHandler {
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public void handleTextMessage(WebSocketSession session, TextMessage message) {
 | 
			
		||||
			// ...
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
There is dedicated WebSocket Java-config and XML namespace support for mapping the above
 | 
			
		||||
WebSocket handler at a specific URL:
 | 
			
		||||
 | 
			
		||||
[source,java,indent=0]
 | 
			
		||||
[subs="verbatim,quotes"]
 | 
			
		||||
----
 | 
			
		||||
	import org.springframework.web.socket.config.annotation.EnableWebSocket;
 | 
			
		||||
	import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
 | 
			
		||||
	import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
 | 
			
		||||
 | 
			
		||||
	@Configuration
 | 
			
		||||
	@EnableWebSocket
 | 
			
		||||
	public class WebSocketConfig implements WebSocketConfigurer {
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
 | 
			
		||||
			registry.addHandler(myHandler(), "/myHandler");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Bean
 | 
			
		||||
		public WebSocketHandler myHandler() {
 | 
			
		||||
			return new MyHandler();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
XML configuration equivalent:
 | 
			
		||||
 | 
			
		||||
[source,xml,indent=0]
 | 
			
		||||
[subs="verbatim,quotes,attributes"]
 | 
			
		||||
----
 | 
			
		||||
	<beans xmlns="http://www.springframework.org/schema/beans"
 | 
			
		||||
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
			
		||||
		xmlns:websocket="http://www.springframework.org/schema/websocket"
 | 
			
		||||
		xsi:schemaLocation="
 | 
			
		||||
			http://www.springframework.org/schema/beans
 | 
			
		||||
			http://www.springframework.org/schema/beans/spring-beans.xsd
 | 
			
		||||
			http://www.springframework.org/schema/websocket
 | 
			
		||||
			http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd">
 | 
			
		||||
 | 
			
		||||
		<websocket:handlers>
 | 
			
		||||
			<websocket:mapping path="/myHandler" handler="myHandler"/>
 | 
			
		||||
		</websocket:handlers>
 | 
			
		||||
 | 
			
		||||
		<bean id="myHandler" class="org.springframework.samples.MyHandler"/>
 | 
			
		||||
 | 
			
		||||
	</beans>
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
The above is for use in Spring MVC applications and should be included in the
 | 
			
		||||
configuration of a <<mvc-serlvet,DispatcherServlet>>. However, Spring's WebSocket
 | 
			
		||||
support does not depend on Spring MVC. It is relatively simple to integrate a `WebSocketHandler`
 | 
			
		||||
into other HTTP serving environments with the help of
 | 
			
		||||
https://github.com/spring-projects/spring-framework/blob/master/spring-websocket/src/main/java/org/springframework/web/socket/server/support/WebSocketHttpRequestHandler.java[WebSocketHttpRequestHandler].
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-server-handshake]]
 | 
			
		||||
==== Customizing the WebSocket Handshake
 | 
			
		||||
The easiest way to customize the initial HTTP WebSocket handshake request is through
 | 
			
		||||
a `HandshakeInterceptor`, which exposes before and after the handshake methods.
 | 
			
		||||
Such an interceptor can be used to preclude the handshake or to make any attributes
 | 
			
		||||
available to the `WebSocketSession`. For example there is a built-in interceptor
 | 
			
		||||
for passing HTTP session attributes to the WebSocket session:
 | 
			
		||||
 | 
			
		||||
[source,java,indent=0]
 | 
			
		||||
[subs="verbatim,quotes"]
 | 
			
		||||
----
 | 
			
		||||
	@Configuration
 | 
			
		||||
	@EnableWebSocket
 | 
			
		||||
	public class WebSocketConfig implements WebSocketConfigurer {
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
 | 
			
		||||
			registry.addHandler(new MyHandler(), "/myHandler")
 | 
			
		||||
				.addInterceptors(new HttpSessionHandshakeInterceptor());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
And the XML configuration equivalent:
 | 
			
		||||
 | 
			
		||||
[source,xml,indent=0]
 | 
			
		||||
[subs="verbatim,quotes,attributes"]
 | 
			
		||||
----
 | 
			
		||||
	<beans xmlns="http://www.springframework.org/schema/beans"
 | 
			
		||||
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
			
		||||
		xmlns:websocket="http://www.springframework.org/schema/websocket"
 | 
			
		||||
		xsi:schemaLocation="
 | 
			
		||||
			http://www.springframework.org/schema/beans
 | 
			
		||||
			http://www.springframework.org/schema/beans/spring-beans.xsd
 | 
			
		||||
			http://www.springframework.org/schema/websocket
 | 
			
		||||
			http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd">
 | 
			
		||||
 | 
			
		||||
		<websocket:handlers>
 | 
			
		||||
			<websocket:mapping path="/myHandler" handler="myHandler"/>
 | 
			
		||||
			<websocket:handshake-interceptors>
 | 
			
		||||
				<bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor"/>
 | 
			
		||||
			</websocket:handshake-interceptors>
 | 
			
		||||
		</websocket:handlers>
 | 
			
		||||
 | 
			
		||||
		<bean id="myHandler" class="org.springframework.samples.MyHandler"/>
 | 
			
		||||
 | 
			
		||||
	</beans>
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
A more advanced option is to extend the `DefaultHandshakeHandler` that performs
 | 
			
		||||
the steps of the WebSocket handshake including  validating the client origin,
 | 
			
		||||
negotiating a sub-protocol, and others. An application may also need to use this
 | 
			
		||||
option if it needs to configure a custom `RequestUpgradeStrategy` in order to
 | 
			
		||||
adapt to a WebSocket server engine and version that is not yet supported
 | 
			
		||||
(also see <<websocket-server-deployment>> for more on this subject).
 | 
			
		||||
Both the Java config and XML namespace make it possible to configure a custom
 | 
			
		||||
`HandshakeHandler`.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-server-decorators]]
 | 
			
		||||
==== WebSocketHandler Decoration
 | 
			
		||||
Spring provides a `WebSocketHandlerDecorator` base class that can be used to decorate
 | 
			
		||||
a `WebSocketHandler` with additional behavior. Logging and exception handling
 | 
			
		||||
implementations are provided and added by default when using the WebSocket Java config
 | 
			
		||||
or XML namespace. The `ExceptionWebSocketHandlerDecorator` catches all uncaught
 | 
			
		||||
exceptions arising from any WebSocketHandler method and closes the WebSocket
 | 
			
		||||
session with status `1011` that indicates a server error.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-server-deployment]]
 | 
			
		||||
==== Deployment Considerations
 | 
			
		||||
The Spring WebSocket API is easy to integrate into a Spring MVC application where
 | 
			
		||||
the `DispatcherServlet` serves both HTTP WebSocket handshake as well as other
 | 
			
		||||
HTTP requests. It is also easy to integrate into other HTTP processing scenarios
 | 
			
		||||
by invoking `WebSocketHttpRequestHandler`. This is convenient and easy to
 | 
			
		||||
understand. However special considerations apply with regards to JSR-356 runtimes.
 | 
			
		||||
 | 
			
		||||
The Java WebSocket API (JSR-356) provides two deployment mechanisms. The first
 | 
			
		||||
involves a Servlet container classpath scan (Servlet 3 feature) at startup and
 | 
			
		||||
the other is a registration API to use at Servlet container initialization.
 | 
			
		||||
Neither of these mechanism make it possible to use a single "front controller"
 | 
			
		||||
for all HTTP processing -- including WebSocket handshake and all other HTTP
 | 
			
		||||
requests -- such as Spring MVC's `DispatcherServlet`.
 | 
			
		||||
 | 
			
		||||
This is a significant limitation of JSR-356 that Spring's WebSocket support
 | 
			
		||||
addresses by providing a server-specific `RequestUpgradeStrategy` even when
 | 
			
		||||
running in a JSR-356 runtime. At present such support is available on
 | 
			
		||||
Tomcat 7.0.47+, Jetty 9.0+, and Glassfish 4.0+. Additional support will be
 | 
			
		||||
added as more WebSocket runtimes become available.
 | 
			
		||||
 | 
			
		||||
[NOTE]
 | 
			
		||||
====
 | 
			
		||||
A request to overcome the above limitation in the Java WebSocket API has been
 | 
			
		||||
created and can be followed at
 | 
			
		||||
https://java.net/jira/browse/WEBSOCKET_SPEC-211[WEBSOCKET_SPEC-211].
 | 
			
		||||
Also note that Tomcat and Jetty already provide native API alternatives that
 | 
			
		||||
makes it easy to overcome the limitation. We are hopeful that more servers
 | 
			
		||||
will follow their example regardless of when it is addressed in the
 | 
			
		||||
Java WebSocket API.
 | 
			
		||||
====
 | 
			
		||||
 | 
			
		||||
A secondary consideration is that Servlet containers with JSR-356 support
 | 
			
		||||
are expected to perform an SCI scan that can slow down application startup
 | 
			
		||||
in some cases dramatically. If a significant impact is observed after an
 | 
			
		||||
upgrade to a Servlet container version with JSR-356 support, it should
 | 
			
		||||
be possible to selectively enable or disable web fragments (and SCI scanning)
 | 
			
		||||
through the use of an `<absolute-ordering />` element in web.xml:
 | 
			
		||||
 | 
			
		||||
[source,xml,indent=0]
 | 
			
		||||
[subs="verbatim,quotes,attributes"]
 | 
			
		||||
----
 | 
			
		||||
	<web-app xmlns="http://java.sun.com/xml/ns/javaee"
 | 
			
		||||
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
			
		||||
		xsi:schemaLocation="
 | 
			
		||||
			http://java.sun.com/xml/ns/javaee
 | 
			
		||||
			http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
 | 
			
		||||
		version="3.0">
 | 
			
		||||
 | 
			
		||||
		<absolute-ordering/>
 | 
			
		||||
 | 
			
		||||
	</web-app>
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
You can then selectively enable web fragments by name, such as Spring's own
 | 
			
		||||
`SpringServletContainerInitializer` that provides support for the Servlet 3
 | 
			
		||||
Java initialization API, if required:
 | 
			
		||||
 | 
			
		||||
[source,xml,indent=0]
 | 
			
		||||
[subs="verbatim,quotes,attributes"]
 | 
			
		||||
----
 | 
			
		||||
	<web-app xmlns="http://java.sun.com/xml/ns/javaee"
 | 
			
		||||
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
			
		||||
		xsi:schemaLocation="
 | 
			
		||||
			http://java.sun.com/xml/ns/javaee
 | 
			
		||||
			http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
 | 
			
		||||
		version="3.0">
 | 
			
		||||
 | 
			
		||||
		<absolute-ordering>
 | 
			
		||||
			<name>spring_web</name>
 | 
			
		||||
		</absolute-ordering>
 | 
			
		||||
 | 
			
		||||
	</web-app>
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-fallback]]
 | 
			
		||||
=== Fallback Options
 | 
			
		||||
As explained in the <<websocket-into-fallback-options,introduction>> WebSocket is not
 | 
			
		||||
supported in all browsers yet or may be precluded by restrictive network proxies.
 | 
			
		||||
This is why Spring provides fallback options that emulate the WebSocket API as close
 | 
			
		||||
as possible based on the https://github.com/sockjs/sockjs-protocol[SockJS protocol].
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-fallback-sockjs-enable]]
 | 
			
		||||
==== Enable SockJS
 | 
			
		||||
SockJS is easy to enable through a configuration:
 | 
			
		||||
 | 
			
		||||
[source,java,indent=0]
 | 
			
		||||
[subs="verbatim,quotes"]
 | 
			
		||||
----
 | 
			
		||||
	@Configuration
 | 
			
		||||
	@EnableWebSocket
 | 
			
		||||
	public class WebSocketConfig implements WebSocketConfigurer {
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
 | 
			
		||||
			registry.addHandler(myHandler(), "/myHandler").withSockJS();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Bean
 | 
			
		||||
		public WebSocketHandler myHandler() {
 | 
			
		||||
			return new MyHandler();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
and the XML configuration equivalent:
 | 
			
		||||
 | 
			
		||||
[source,xml,indent=0]
 | 
			
		||||
[subs="verbatim,quotes,attributes"]
 | 
			
		||||
----
 | 
			
		||||
	<beans xmlns="http://www.springframework.org/schema/beans"
 | 
			
		||||
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
			
		||||
		xmlns:websocket="http://www.springframework.org/schema/websocket"
 | 
			
		||||
		xsi:schemaLocation="
 | 
			
		||||
			http://www.springframework.org/schema/beans
 | 
			
		||||
			http://www.springframework.org/schema/beans/spring-beans.xsd
 | 
			
		||||
			http://www.springframework.org/schema/websocket
 | 
			
		||||
			http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd">
 | 
			
		||||
 | 
			
		||||
		<websocket:handlers>
 | 
			
		||||
			<websocket:mapping path="/myHandler" handler="myHandler"/>
 | 
			
		||||
			<websocket:sockjs/>
 | 
			
		||||
		</websocket:handlers>
 | 
			
		||||
 | 
			
		||||
		<bean id="myHandler" class="org.springframework.samples.MyHandler"/>
 | 
			
		||||
 | 
			
		||||
	</beans>
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
The above is for use in Spring MVC applications and should be included in the
 | 
			
		||||
configuration of a <<mvc-serlvet,DispatcherServlet>>. However, Spring's WebSocket
 | 
			
		||||
and SockJS support does not depend on Spring MVC. It is relatively simple to
 | 
			
		||||
integrate into other HTTP serving environments with the help of
 | 
			
		||||
https://github.com/spring-projects/spring-framework/blob/master/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/SockJsHttpRequestHandler.java[SockJsHttpRequestHandler].
 | 
			
		||||
 | 
			
		||||
On the browser side, applications can use the
 | 
			
		||||
https://github.com/sockjs/sockjs-client[sockjs-client] that emulates the W3C
 | 
			
		||||
WebSocket API and communicates with the server to select the best
 | 
			
		||||
transport option depending on the browser it's running in. Review the
 | 
			
		||||
https://github.com/sockjs/sockjs-client[sockjs-client] page and the list of
 | 
			
		||||
transport types supported by browser. The client also provides several
 | 
			
		||||
configuration options, for example to specify which transports to include.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-fallback-sockjs-explained]]
 | 
			
		||||
==== How SockJS Works
 | 
			
		||||
An in-depth description of how SockJS works is beyond the scope of this document.
 | 
			
		||||
This section summarizes a few key facts to aid with understanding.
 | 
			
		||||
The SockJS protocol itself is defined in a
 | 
			
		||||
https://github.com/sockjs/sockjs-protocol/blob/master/sockjs-protocol-0.3.3.py[test suite]
 | 
			
		||||
with comments explaining the protocol. There is also an
 | 
			
		||||
http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html[HTML version of that test]
 | 
			
		||||
showing comments on the right and code on the left.
 | 
			
		||||
 | 
			
		||||
The SockJS client issues HTTP requests with this URL structure:
 | 
			
		||||
 | 
			
		||||
.SockJS URL
 | 
			
		||||
----
 | 
			
		||||
http://host:port/{path-to-sockjs-endpoint}/{server-id}/{session-id}/{transport}
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
The WebSocket transport type uses a single HTTP connection to perform a
 | 
			
		||||
WebSocket handshake and establish an actual WebSocket session. HTTP-based
 | 
			
		||||
transports on the other hand must simulate the WebSocket API and at any time
 | 
			
		||||
may use two HTTP connections -- one for server-to-client messages, via
 | 
			
		||||
https://spring.io/blog/2012/05/08/spring-mvc-3-2-preview-techniques-for-real-time-updates[HTTP streaming or long polling],
 | 
			
		||||
and another for sending client messages to the server via HTTP POST.
 | 
			
		||||
 | 
			
		||||
The session id is useful with HTTP transports to associate individual HTTP
 | 
			
		||||
requests that belong to the same SockJS session. The server id is not used in the
 | 
			
		||||
protocol but is added to help in clustered environments.
 | 
			
		||||
 | 
			
		||||
SockJS adds a minimal amount of message framing. For example the server can send
 | 
			
		||||
an "open frame" (the letter +o+), a "heartbeat frame" (the letter +h+), or a
 | 
			
		||||
"close frame" (the letter +c+) while the client sends messages as a JSON-encoded
 | 
			
		||||
array prepended with the letter "a" (e.g. +a["message1","message2"]+).
 | 
			
		||||
 | 
			
		||||
By default the server sends a heartbeat frame every 25 seconds to keep proxies
 | 
			
		||||
and loadbalancers from timing out the connection.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-fallback-sockjs-spring]]
 | 
			
		||||
==== Spring's SockJS Support
 | 
			
		||||
In the Spring Framework, server-side support for the SockJS protocol is provided through a
 | 
			
		||||
hierarchy of classes that implement the `SockJsService` interface while
 | 
			
		||||
`SockJsHttpRequestHandler` integrates the service into HTTP request processing.
 | 
			
		||||
 | 
			
		||||
To implement HTTP streaming and long polling both of which require an HTTP connection
 | 
			
		||||
to remain open longer than usual, in Servlet containers Spring's SockJS support
 | 
			
		||||
relies on Servlet 3 async support.
 | 
			
		||||
 | 
			
		||||
[WARNING]
 | 
			
		||||
====
 | 
			
		||||
Servlet 3 async support does not expose a notification when a client disconnects,
 | 
			
		||||
e.g. a browser tab is closed, page is refreshed, etc
 | 
			
		||||
(see https://java.net/jira/browse/SERVLET_SPEC-44[SERVLET_SPEC-44]). However, the
 | 
			
		||||
Serlvet container will usually raise an IOException on the next attempt to write
 | 
			
		||||
to the response at which point the SockJS session will be closed. Since the
 | 
			
		||||
SockJsService sends a heartbeat every 25 seconds, typically a disconnected
 | 
			
		||||
client will be detected within that time period.
 | 
			
		||||
====
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-stomp]]
 | 
			
		||||
=== STOMP Messaging
 | 
			
		||||
The WebSocket protocol defines two main types of messages -- text and binary --
 | 
			
		||||
but leaves their content undefined. Instead it's expected that client and
 | 
			
		||||
server may agree on using a sub-protocol, i.e. a higher-level protocol that defines
 | 
			
		||||
the message content. Using a sub-protocol is optional but either way client
 | 
			
		||||
and server both need to understand how to interpret messages.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-stomp-overview]]
 | 
			
		||||
==== STOMP Overview
 | 
			
		||||
http://stomp.github.io/stomp-specification-1.2.html#Abstract[STOMP] is a simple
 | 
			
		||||
messaging protocol originally created to connect to enterprise message brokers from
 | 
			
		||||
scripting languages such as Ruby, Python and Perl. It is designed to address a
 | 
			
		||||
subset of commonly used patterns in messaging protocols. STOMP can be used over
 | 
			
		||||
any reliable 2-way streaming network protocol such as TCP and WebSocket.
 | 
			
		||||
 | 
			
		||||
STOMP is a frame based protocol with frames modelled on HTTP. This is the
 | 
			
		||||
structure of a frame:
 | 
			
		||||
 | 
			
		||||
----
 | 
			
		||||
COMMAND
 | 
			
		||||
header1:value1
 | 
			
		||||
header2:value2
 | 
			
		||||
 | 
			
		||||
Body^@
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
For example a client can use the +SEND+ command to send a message or the
 | 
			
		||||
+SUBSCRIBE+ command to express interest in receiving messages. Both of these commands
 | 
			
		||||
require a +"destination"+ header that indicates where to send a message to or likewise
 | 
			
		||||
what to subscribe to.
 | 
			
		||||
 | 
			
		||||
Here is an example of a client sending a request to buy stock shares:
 | 
			
		||||
 | 
			
		||||
----
 | 
			
		||||
SEND
 | 
			
		||||
destination:/queue/trade
 | 
			
		||||
content-type:application/json
 | 
			
		||||
content-length:44
 | 
			
		||||
 | 
			
		||||
{"action":"BUY","ticker":"MMM","shares",44}^@
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
Here is an example of a client subscribing to receive stock quotes:
 | 
			
		||||
----
 | 
			
		||||
SUBSCRIBE
 | 
			
		||||
id:sub-1
 | 
			
		||||
destination:/topic/price.stock.*
 | 
			
		||||
 | 
			
		||||
^@
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
[NOTE]
 | 
			
		||||
====
 | 
			
		||||
The meaning of a destination is intentionally left opaque in the STOMP spec. It can
 | 
			
		||||
be any string and it's entirely up to STOMP servers to define the semantics and
 | 
			
		||||
the syntax of destinations they support. It is very common however for destinations
 | 
			
		||||
to be path-like strings where "/topic/.." implies publish-subscribe (one-to-many)
 | 
			
		||||
and "/queue/" to implies point-to-point (one-to-one) message exchanges.
 | 
			
		||||
====
 | 
			
		||||
 | 
			
		||||
STOMP servers can use the +MESSAGE+ command to broadcast messages to all subscribers.
 | 
			
		||||
Here is an example of a server sending a stock quote to a subscribed client:
 | 
			
		||||
 | 
			
		||||
----
 | 
			
		||||
MESSAGE
 | 
			
		||||
message-id:nxahklf6-1
 | 
			
		||||
subscription:sub-1
 | 
			
		||||
destination:/topic/price.stock.MMM
 | 
			
		||||
 | 
			
		||||
{"ticker":"MMM","price":129.45}^@
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
[NOTE]
 | 
			
		||||
====
 | 
			
		||||
It's important to know that a server cannot send unsolicited messages.
 | 
			
		||||
All messages from a server must be in response to a specific client subscription
 | 
			
		||||
and the +"subscription-id"+ header of the server message must match
 | 
			
		||||
the +"id"+ header of the client subscription.
 | 
			
		||||
====
 | 
			
		||||
 | 
			
		||||
The above overview is intended to provide the most basic understanding of the
 | 
			
		||||
STOMP protocol. It is recommended to review the protocol
 | 
			
		||||
http://stomp.github.io/stomp-specification-1.2.html[specification], which is
 | 
			
		||||
easy to follow and manageable in terms of size.
 | 
			
		||||
 | 
			
		||||
The following summarizes the benefits for an application from using STOMP over WebSocket:
 | 
			
		||||
 | 
			
		||||
* Standard message format
 | 
			
		||||
* Application-level protocol with support for common messaging patterns
 | 
			
		||||
* Client-side support, e.g. https://github.com/jmesnil/stomp-websocket[stomp.js], https://github.com/cujojs/msgs[msgs.js]
 | 
			
		||||
* The ability to interpret, route, and process messages on both client and server-side
 | 
			
		||||
* The option to plug a message broker -- RabbitMQ, ActiveMQ, many others -- to broadcast messages (explained later)
 | 
			
		||||
 | 
			
		||||
Most importantly the use of STOMP (vs plain WebSocket) enables the Spring Framework
 | 
			
		||||
to provide a programming model for application-level use in the same way that
 | 
			
		||||
Spring MVC provides a programming model based on HTTP.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-stomp-enable]]
 | 
			
		||||
==== Enable STOMP over WebSocket
 | 
			
		||||
The Spring Framework provides support for using STOMP over WebSocket through
 | 
			
		||||
the +spring-messaging+ and +spring-websocket+ modules. It's easy to enable it.
 | 
			
		||||
 | 
			
		||||
Here is an example of configuring a STOMP WebSocket endpoint with SockJS fallback
 | 
			
		||||
options. The endpoint is available for clients to connect to at URL path "/portfolio":
 | 
			
		||||
 | 
			
		||||
[source,java,indent=0]
 | 
			
		||||
[subs="verbatim,quotes"]
 | 
			
		||||
----
 | 
			
		||||
	import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
 | 
			
		||||
	import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
 | 
			
		||||
 | 
			
		||||
	@Configuration
 | 
			
		||||
	@EnableWebSocketMessageBroker
 | 
			
		||||
	public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public void registerStompEndpoints(StompEndpointRegistry registry) {
 | 
			
		||||
			registry.addEndpoint("/portfolio").withSockJS();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// ...
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
XML configuration equivalent:
 | 
			
		||||
 | 
			
		||||
[source,xml,indent=0]
 | 
			
		||||
[subs="verbatim,quotes,attributes"]
 | 
			
		||||
----
 | 
			
		||||
	<beans xmlns="http://www.springframework.org/schema/beans"
 | 
			
		||||
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
			
		||||
		xmlns:websocket="http://www.springframework.org/schema/websocket"
 | 
			
		||||
		xsi:schemaLocation="
 | 
			
		||||
			http://www.springframework.org/schema/beans
 | 
			
		||||
			http://www.springframework.org/schema/beans/spring-beans.xsd
 | 
			
		||||
			http://www.springframework.org/schema/websocket
 | 
			
		||||
			http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd">
 | 
			
		||||
 | 
			
		||||
		<websocket:message-broker>
 | 
			
		||||
			<websocket:stomp-endpoint path="/portfolio" />
 | 
			
		||||
				<websocket:sockjs/>
 | 
			
		||||
			</websocket:stomp-endpoint>
 | 
			
		||||
			...
 | 
			
		||||
		</websocket:message-broker>
 | 
			
		||||
 | 
			
		||||
	</beans>
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
On the browser side, a client might connect as follows using
 | 
			
		||||
https://github.com/jmesnil/stomp-websocket[stomp.js] and the
 | 
			
		||||
https://github.com/sockjs/sockjs-client[sockjs-client]:
 | 
			
		||||
 | 
			
		||||
[source,javascript,indent=0]
 | 
			
		||||
[subs="verbatim,quotes"]
 | 
			
		||||
----
 | 
			
		||||
	var socket = new SockJS("/spring-websocket-portfolio/portfolio");
 | 
			
		||||
	var stompClient = Stomp.over(socket);
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
Or if connecting via WebSocket (without SockJS):
 | 
			
		||||
 | 
			
		||||
[source,javascript,indent=0]
 | 
			
		||||
[subs="verbatim,quotes"]
 | 
			
		||||
----
 | 
			
		||||
	var socket = new WebSocket("/spring-websocket-portfolio/portfolio");
 | 
			
		||||
	var stompClient = Stomp.over(socket);
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[websocket-stomp-handle]]
 | 
			
		||||
==== Handling STOMP Messages
 | 
			
		||||
When STOMP is enabled, the Spring application is effectively becomes a STOMP
 | 
			
		||||
broker to connected clients.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[spring-integration]]
 | 
			
		||||
= Integration
 | 
			
		||||
[partintro]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue