@@ -944,7 +944,7 @@ to use in applications along with an annotation programming model for routing an
944
944
processing STOMP messages from WebSocket clients. As a result an `@Controller`
945
945
can now contain both `@RequestMapping` and `@MessageMapping` methods for handling
946
946
HTTP requests and messages from WebSocket-connected clients. The new `spring-messaging`
947
- module also contains key abstractions from the
947
+ module also contains key abstractions formerly from the
948
948
http://projects.spring.io/spring-integration/[Spring Integration] project such as
949
949
`Message`, `MessageChannel`, `MessageHandler`, and others to serve as a foundation
950
950
for messaging-based applications.
@@ -36685,7 +36685,7 @@ and also provides additional value-add as explained in the rest of the introduct
36685
36685
36686
36686
36687
36687
[[websocket-into-fallback-options]]
36688
- ==== Fallback Options
36688
+ ==== WebSocket Fallback Options
36689
36689
An important challenge to adoption is the lack of support for WebSocket in some
36690
36690
browsers. Notably the first Internet Explorer version to support WebSocket is
36691
36691
version 10 (see http://caniuse.com/websockets for support by browser versions).
@@ -36707,7 +36707,7 @@ modifying the application otherwise.
36707
36707
36708
36708
36709
36709
[[websocket-intro-architecture]]
36710
- ==== Messaging Architecture
36710
+ ==== A Messaging Architecture
36711
36711
Aside from short-to-midterm adoption challenges, using WebSocket
36712
36712
brings up important design considerations that are important to recognize
36713
36713
early on, especially in contrast to what we know about building web applications today.
@@ -36734,7 +36734,7 @@ annotation based programming model.
36734
36734
36735
36735
36736
36736
[[websocket-intro-sub-protocol]]
36737
- ==== Sub-Protocol Support
36737
+ ==== Sub-Protocol Support in WebSocket
36738
36738
WebSocket does imply a __messaging architecture__ but does not mandate the
36739
36739
use of any specific __messaging protocol__. It is a very thin layer over TCP
36740
36740
that transforms a stream of bytes into a stream of messages
@@ -36767,7 +36767,7 @@ WebSocket and over the web.
36767
36767
36768
36768
36769
36769
[[websocket-intro-when-to-use]]
36770
- ==== When To Use WebSocket?
36770
+ ==== Should I Use WebSocket?
36771
36771
With all the design considerations surrounding the use of WebSocket, it is
36772
36772
reasonable to ask when is it appropriate to use?
36773
36773
@@ -36810,7 +36810,7 @@ WebSocket clients or to a specific user.
36810
36810
36811
36811
36812
36812
[[websocket-server]]
36813
- === WebSocket Server
36813
+ === WebSocket API
36814
36814
The Spring Framework provides a WebSocket API designed to adapt to various WebSocket engines.
36815
36815
For example, it runs on JSR-356 runtimes such as Tomcat (7.0.47+), GlassFish (4.0+) and
36816
36816
WildFly (8.0+) but can also adapt to other WebSocket runtimes such as the Jetty (9.1+)
@@ -37448,7 +37448,7 @@ log category to TRACE.
37448
37448
====
37449
37449
37450
37450
[[websocket-fallback-cors]]
37451
- ==== CORS Headers for SockJS Requests
37451
+ ==== CORS Headers for SockJS
37452
37452
37453
37453
The SockJS protocol uses CORS for cross-domain support in the XHR streaming and
37454
37454
polling transports. Therefore CORS headers are added automatically unless the
@@ -37472,7 +37472,7 @@ SockJS endpoint prefix thus letting Spring's SockJsService handle it.
37472
37472
37473
37473
37474
37474
[[websocket-stomp]]
37475
- === STOMP Messaging
37475
+ === STOMP Over WebSocket Messaging Architecture
37476
37476
The WebSocket protocol defines two main types of messages -- text and binary --
37477
37477
but leaves their content undefined. Instead it's expected that client and
37478
37478
server may agree on using a sub-protocol, i.e. a higher-level protocol that defines
@@ -37575,7 +37575,7 @@ Spring MVC provides a programming model based on HTTP.
37575
37575
37576
37576
37577
37577
[[websocket-stomp-enable]]
37578
- ==== Enable STOMP ( over WebSocket)
37578
+ ==== Enable STOMP over WebSocket
37579
37579
The Spring Framework provides support for using STOMP over WebSocket through
37580
37580
the +spring-messaging+ and +spring-websocket+ modules. It's easy to enable it.
37581
37581
@@ -37666,56 +37666,65 @@ sections <<websocket-stomp-handle-broker-relay-configure>> and
37666
37666
37667
37667
37668
37668
[[websocket-stomp-handle]]
37669
- ==== Overview of STOMP Message Handling
37670
-
37671
- When a STOMP endpoint is configured, the Spring application effectively becomes
37672
- the broker to connected clients, handling incoming messages and broadcasting
37673
- messages back to them. This part of the documentation describes how STOMP
37674
- messages are handled within the application.
37675
-
37676
- As mentioned in the <<websocket-intro-architecture,introduction>> the
37677
- `spring-messaging` module contains key abstractions from the
37678
- https://spring.io/spring-integration[Spring Integration] project, including
37679
- `Message`, `MessageChannel`, `MessageHandler` and a few others.
37680
-
37681
- [NOTE]
37682
- ====
37683
- Spring Integration 4 will be the first version to start using the abstractions
37684
- from the package structure of the `spring-messaging` module as opposed to its
37685
- own present packages. Spring Integration also provides many additional
37686
- abstractions and implementations in support of the well-known
37687
- EAI patterns (http://www.eaipatterns.com/[enterprise integration patterns]).
37688
- ====
37689
-
37690
- {javadoc-baseurl}/org/springframework/messaging/MessageChannel.html[MessageChannel]
37691
- is a simple contract for passing messages between components without
37692
- creating tight coupling among them.
37693
- {javadoc-baseurl}/org/springframework/messaging/SubscribableChannel.html[SubscribableChannel] extends
37694
- it, with the ability to register subscribers; and
37695
- {javadoc-baseurl}/org/springframework/messaging/support/ExecutorSubscribableChannel.html[ExecutorSubscribableChannel]
37696
- is an implementation that passes messages to subscribers in
37697
- the same thread or a different thread depending on whether it has been provided with
37698
- a `java.util.concurrent.Executor`. This enables assembling message
37699
- handling flows from various components and modifying them through configuration.
37700
-
37701
- The provided Java-config `@EnableWebSocketMessageBroker` and XML namespace
37702
- `<websocket:message-broker>` each put together a default message handling
37703
- flow for applications to use, as explained next. This flow can be modified,
37704
- customized, or extended. For example, an application can add a
37705
- {javadoc-baseurl}/org/springframework/messaging/support/ChannelInterceptor.html[ChannelInterceptor]
37706
- to any message channel in order to intercept messages passing through it;
37707
- it can register additional message handling components, alternate between
37708
- synchronous and asynchronous message passing, and so on.
37709
-
37710
- Incoming client STOMP messages are passed to a message channel with the name
37711
- `"clientInboundChannel"`. By default the messages are routed to annotated
37712
- methods as well as to a "simple" message broker. This simple message broker
37713
- automatically records subscriptions, in-memory, and broadcasts messages as
37714
- necessary. As explained later, you can also use a full-featured message broker
37715
- (e.g. RabbitMQ, ActiveMQ, and any other broker that supports STOMP) to manage
37716
- subscriptions and broadcast messages.
37717
-
37718
- Below is example configuration:
37669
+ ==== Flow of Messages
37670
+
37671
+ When a STOMP endpoint is configured, the Spring application becomes the broker to
37672
+ connected clients. It handles incoming messages and broadcasts messages back.
37673
+ This section provides the big picture of how messages are handled and how
37674
+ they flow inside the application.
37675
+
37676
+ The `spring-messaging` module contains a number of abstractions for use in
37677
+ messaging applications which originated in the
37678
+ https://spring.io/spring-integration[Spring Integration] project and
37679
+ have been in use for a long time but are now part of the Spring Framework.
37680
+ Listed below are some of the main building blocks:
37681
+
37682
+ * {javadoc-baseurl}/org/springframework/messaging/Message.html[Message]
37683
+ represents a message with headers and a payload.
37684
+ * {javadoc-baseurl}/org/springframework/messaging/MessageHandler.html[MessageHandler]
37685
+ a simple contract components that handle a message.
37686
+ * {javadoc-baseurl}/org/springframework/messaging/MessageChannel.html[MessageChannel]
37687
+ a simple contract for sending a message that enables loose coupling between
37688
+ senders and receivers.
37689
+ * {javadoc-baseurl}/org/springframework/messaging/SubscribableChannel.html[SubscribableChannel]
37690
+ extends `MessageChannel` and sends messages to registered `MessageHandler` subscribers.
37691
+ * {javadoc-baseurl}/org/springframework/messaging/support/ExecutorSubscribableChannel.html[ExecutorSubscribableChannel]
37692
+ a concrete implementation of `SubscribableChannel` that can deliver messages
37693
+ asynchronously using threads from a thread pool.
37694
+
37695
+ The above building blocks can be used to construct a message flow.
37696
+
37697
+ The provided configuration for STOMP over WebSocket, both Java config and XML namespace,
37698
+ assemble just such a concrete message flow that consists of the following 3
37699
+ subscribable channels:
37700
+
37701
+ * `"clientInboundChannel"` for messages from WebSocket clients; every incoming
37702
+ WebSocket message that is decoded and turned into a Spring Message representing
37703
+ a STOMP frame is passed through this channel.
37704
+ * `"clientOutboundChannel"` for messages to WebSocket clients; every outgoing
37705
+ Spring Message representing a STOMP frame that is encoded and sent as a
37706
+ WebSocket message is passed through this channel.
37707
+ * `"brokerChannel"` for messages to the broker from within the application and
37708
+ ultimately intended to reach connected clients; every message that the application
37709
+ wants to send to clients passes through this channel.
37710
+
37711
+ Messages through `"clientInboundChannel"` can flow to annotated
37712
+ methods for application handling (e.g. a stock trade execution request) or can
37713
+ be forwarded to the broker (e.g. client subscribing for stock quotes).
37714
+ The STOMP destination is used for simple prefix-based routing. For example
37715
+ the "/app" prefix routes messages annotated methods while the "/topic" or
37716
+ "/queue" prefix route messages to the broker.
37717
+
37718
+ When a message-handling annotated method has a return type, its return
37719
+ value is sent as the payload of a Spring Message to the `"brokerChannel"`.
37720
+ The broker in turn broadcasts the message to clients. Sending an object as
37721
+ the payload of a Message to a specific destination can also easily be done
37722
+ from anywhere in the application with the help of a messaging template.
37723
+ For example a an HTTP POST handling method can broadcast a message to
37724
+ connected clients or a service component may periodically broadcast
37725
+ stock quotes.
37726
+
37727
+ Below is a simple example to illustrate the flow of messages:
37719
37728
37720
37729
[source,java,indent=0]
37721
37730
[subs="verbatim,quotes"]
@@ -37726,96 +37735,49 @@ Below is example configuration:
37726
37735
37727
37736
@Override
37728
37737
public void registerStompEndpoints(StompEndpointRegistry registry) {
37729
- registry.addEndpoint("/portfolio").withSockJS() ;
37738
+ registry.addEndpoint("/portfolio");
37730
37739
}
37731
37740
37732
37741
@Override
37733
37742
public void configureMessageBroker(MessageBrokerRegistry registry) {
37734
- registry.enableSimpleBroker("/topic/");
37735
37743
registry.setApplicationDestinationPrefixes("/app");
37744
+ registry.enableSimpleBroker("/topic/");
37736
37745
}
37737
37746
37738
37747
}
37739
- ----
37740
-
37741
- XML configuration equivalent:
37742
37748
37743
- [source,xml,indent=0]
37744
- [subs="verbatim,quotes,attributes"]
37745
- ----
37746
- <beans xmlns="http://www.springframework.org/schema/beans"
37747
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
37748
- xmlns:websocket="http://www.springframework.org/schema/websocket"
37749
- xsi:schemaLocation="
37750
- http://www.springframework.org/schema/beans
37751
- http://www.springframework.org/schema/beans/spring-beans.xsd
37752
- http://www.springframework.org/schema/websocket
37753
- http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd">
37754
-
37755
- <websocket:message-broker application-destination-prefix="/app">
37756
- <websocket:stomp-endpoint path="/portfolio" />
37757
- <websocket:sockjs/>
37758
- </websocket:stomp-endpoint>
37759
- <websocket:simple-broker prefix="/topic"/>
37760
- </websocket:message-broker>
37761
-
37762
- </beans>
37763
- ----
37764
-
37765
- The configuration example assigns destination prefixes -- `/app` for filtering
37766
- messages to annotated methods and `/topic` for messages to the broker. The
37767
- examples below demonstrate how this can be used.
37768
-
37769
- The destination prefix should not be included in annotation mappings. For
37770
- example, this method handles messages to destination `/app/greetings`:
37771
-
37772
- [source,java,indent=0]
37773
- [subs="verbatim,quotes"]
37774
- ----
37775
37749
@Controller
37776
37750
public class GreetingController {
37777
37751
37778
- @MessageMapping("/greetings ") {
37779
- public void handle(String greeting) {
37780
- // ...
37752
+ @MessageMapping("/greeting ") {
37753
+ public String handle(String greeting) {
37754
+ return "[" + getTimestamp() + ": " + greeting;
37781
37755
}
37782
37756
37783
37757
}
37784
37758
37785
37759
----
37786
37760
37787
- The method accepts a String extracted from the payload of the message,
37788
- possibly converted based on its content type. The method can also return a
37789
- value, which is wrapped as the payload of a new message and sent to a message
37790
- channel named `"brokerChannel"` (which is used for sending messages to the broker
37791
- from within the application). The new message is sent to the same destination
37792
- as that of the client message, but with the default prefix `/topic`
37793
- (you can also use `@SendTo` for any other target destination):
37761
+ The following explains how messages flow given the above:
37794
37762
37795
- [source,java,indent=0]
37796
- [subs="verbatim,quotes"]
37797
- ----
37798
- @Controller
37799
- public class GreetingController {
37800
-
37801
- @MessageMapping("/greetings") {
37802
- public String handle(String greeting) {
37803
- return "[" + getTimestamp() + ": " + greeting;
37804
- }
37763
+ * WebSocket clients connect to the WebSocket endpoint at "/portfolio".
37764
+ * Subscriptions to "/topic/greeting" pass through the "clientInboundChannel"
37765
+ and are forwarded to the broker.
37766
+ * Greetings sent to "/app/greeting" pass through the "clientInboundChannel"
37767
+ and are forwarded to the ` GreetingController`. The controller adds the current
37768
+ time and the return value is passed through the "brokerChannel" as message
37769
+ to "/topic/greeting" (destination is selected based on a convention but can be
37770
+ overridden via `@SendTo`).
37771
+ * The broker in turn broadcasts messages to subscribers and they pass through
37772
+ the `"clientOutboundChannel"`.
37805
37773
37806
- }
37774
+ The next section provides more details on annotated methods including the
37775
+ kinds of arguments and return values supported.
37807
37776
37808
- ----
37809
-
37810
- As a result, to put it all together, a client sends a greeting message to
37811
- destination `/app/greetings`. The message is routed to `GreetingController`,
37812
- which enriches the greeting with a timestamp and sends a new message to the
37813
- broker with destination `/topic/greetings`. The broker then broadcasts the
37814
- message to all subscribed, connected clients.
37815
37777
37816
37778
37817
37779
[[websocket-stomp-handle-annotations]]
37818
- ===== Annotation-based Message Handling
37780
+ ==== Annotation Message Handling
37819
37781
37820
37782
The `@MessageMapping` annotation is supported on methods of `@Controller`
37821
37783
as well as on `@RestController`-annotated classes.
@@ -37873,7 +37835,7 @@ the specified target destination.
37873
37835
37874
37836
37875
37837
[[websocket-stomp-handle-send]]
37876
- ===== Sending Messages From Anywhere
37838
+ ==== Sending Messages
37877
37839
37878
37840
What if you wanted to send messages to connected clients from any part of the
37879
37841
application? Any application component can send messages to the `"brokerChannel"`.
@@ -37908,7 +37870,7 @@ bean of the same type exists.
37908
37870
37909
37871
37910
37872
[[websocket-stomp-handle-simple-broker]]
37911
- ===== Simple Message Broker
37873
+ ==== Simple Broker
37912
37874
37913
37875
The built-in, simple, message broker handles subscription requests from clients,
37914
37876
stores them in memory, and broadcasts messages to connected clients with matching
@@ -37917,7 +37879,7 @@ to Ant-style destination patterns.
37917
37879
37918
37880
37919
37881
[[websocket-stomp-handle-broker-relay]]
37920
- ===== Using a Full-Featured Message Broker
37882
+ ==== Full-Featured Broker
37921
37883
37922
37884
The simple broker is great for getting started but supports only a subset of
37923
37885
STOMP commands (e.g. no acks, receipts, etc), relies on a simple message
@@ -37998,7 +37960,7 @@ subscribed WebSocket clients.
37998
37960
In effect, the broker relay enables robust and scalable message broadcasting.
37999
37961
38000
37962
[[websocket-stomp-handle-broker-relay-configure]]
38001
- ===== Configuring Connections To The Full-Featured Broker
37963
+ ==== Connections To Full-Featured Broker
38002
37964
38003
37965
A STOMP broker relay maintains a single "system" TCP connection to the broker.
38004
37966
This connection is used for messages originating from the server-side application
@@ -38043,7 +38005,7 @@ the TCP connection is established is different from the host providing the
38043
38005
cloud-based STOMP service.
38044
38006
38045
38007
[[websocket-stomp-handle-user]]
38046
- ===== Authentication and Handling Messages to User Destinations
38008
+ ==== Authentication and User Destinations
38047
38009
38048
38010
An application can also send messages targeting a specific user.
38049
38011
@@ -38083,8 +38045,10 @@ So in that case the client could subscribe to `/user/exchange/amq.direct/positio
38083
38045
ActiveMQ has http://activemq.apache.org/delete-inactive-destinations.html[configuration options]
38084
38046
for purging inactive destinations.
38085
38047
38048
+
38049
+
38086
38050
[[websocket-stomp-testing]]
38087
- ===== Testing Message Handling Controllers
38051
+ ==== Testing Annotated Controller Methods
38088
38052
38089
38053
There are two main approaches to testing applications using Spring's STOMP over
38090
38054
WebSocket support. The first is to write server-side tests verifying the functionality
0 commit comments