@@ -984,24 +984,27 @@ public class WebSocketConfig extends WebSocketMessageBrokerConfigurationSupport
984984
985985[[websocket-stomp]]
986986== STOMP Over WebSocket Messaging Architecture
987- The WebSocket protocol defines two main types of messages -- text and binary --
988- but leaves their content undefined. Instead it's expected that the client and
989- server may agree on using a sub-protocol, i.e. a higher-level protocol that defines
990- the message content. Using a sub-protocol is optional but either way the client
991- and server both need to understand how to interpret messages.
987+ The WebSocket protocol defines two types of messages, text and binary, but their
988+ content is undefined. It's expected that the client and server may agree on using
989+ a sub-protocol (i.e. a higher-level protocol) to define message semantics.
990+ While the use of a sub-protocol with WebSocket is completely optional either way
991+ client and server will need to agree on some kind of protocol to help interpret
992+ messages.
992993
993994
994995
995996[[websocket-stomp-overview]]
996997=== Overview of STOMP
997998http://stomp.github.io/stomp-specification-1.2.html#Abstract[STOMP] is a simple
998999text-oriented messaging protocol that was originally created for scripting languages
999- (such as Ruby, Python, and Perl) to connect to enterprise message brokers. It is
1000- designed to address a subset of commonly used patterns in messaging protocols. STOMP
1001- can be used over any reliable 2-way streaming network protocol such as TCP and WebSocket.
1000+ such as Ruby, Python, and Perl to connect to enterprise message brokers. It is
1001+ designed to address a subset of commonly used messaging patterns. STOMP can be
1002+ used over any reliable 2-way streaming network protocol such as TCP and WebSocket.
1003+ Although STOMP is a text-oriented protocol, the payload of messages can be
1004+ either text or binary.
10021005
1003- STOMP is a frame based protocol with  frames modeled on HTTP. This is the 
1004- structure  of a frame:
1006+ STOMP is a frame based protocol whose  frames are  modeled on HTTP. The structure 
1007+ of a STOMP  frame:
10051008
10061009---- 
10071010COMMAND 
@@ -1011,23 +1014,28 @@ header2:value2
10111014Body^@ 
10121015---- 
10131016
1014- For example, a client can use the +SEND+ command to send a message or the
1015- +SUBSCRIBE+ command to express interest in receiving messages. Both of these commands
1016- require a +"destination"+ header that indicates where to send a message, or likewise
1017- what to subscribe to.
1017+ Clients can use the +SEND+ or +SUBSCRIBE+ commands to send or subscribe for
1018+ messages along with a +"destination"+ header that describes what the
1019+ message is about and who should receive it. This enables a simple
1020+ publish-subscribe mechanism that can be used to send messages through the broker
1021+ to other connected clients or to send messages to the server to request that
1022+ some work be performed.
10181023
1019- Here is an example of a client sending a request to buy stock shares:
1024+ When using Spring's STOMP support, the Spring WebSocket application acts
1025+ as the STOMP broker to clients. Messages are routed to `@Controller` message-handling
1026+ methods or to a simple, in-memory broker that keeps track of subscriptions and
1027+ broadcasts messages to subscribed users. You can also configure Spring to work
1028+ with a dedicated STOMP broker (e.g. RabbitMQ, ActiveMQ, etc) for the actual
1029+ broadcasting of messages. In that case Spring maintains
1030+ TCP connections to the broker, relays messages to it, and also passes messages
1031+ from it down to connected WebSocket clients. Thus Spring web applications can
1032+ rely on unified HTTP-based security, common validation, and a familiar programming
1033+ model message-handling work.
10201034
1021- ---- 
1022- SEND 
1023- destination:/queue/trade 
1024- content-type:application/json 
1025- content-length:44 
1026- 
1027- {"action":"BUY","ticker":"MMM","shares",44}^@ 
1028- ---- 
1035+ Here is an example of a client subscribing to receive stock quotes which
1036+ the server may emit periodically e.g. via a scheduled task sending messages
1037+ through a `SimpMessagingTemplate` to the broker:
10291038
1030- Here is an example of a client subscribing to receive stock quotes:
10311039---- 
10321040SUBSCRIBE 
10331041id:sub-1 
@@ -1036,15 +1044,25 @@ destination:/topic/price.stock.*
10361044^@ 
10371045---- 
10381046
1039- [NOTE]
1040- ==== 
1047+ Here is an example of a client sending a trade request, which the server
1048+ may handle through an `@MessageMapping` method and later on, after the execution,
1049+ broadcast a trade confirmation message and details down to the client:
1050+ 
1051+ ---- 
1052+ SEND 
1053+ destination:/queue/trade 
1054+ content-type:application/json 
1055+ content-length:44 
1056+ 
1057+ {"action":"BUY","ticker":"MMM","shares",44}^@ 
1058+ ---- 
1059+ 
10411060The meaning of a destination is intentionally left opaque in the STOMP spec. It can
10421061be any string, and it's entirely up to STOMP servers to define the semantics and
10431062the syntax of the destinations that they support. It is very common, however, for
10441063destinations to be path-like strings where `"/topic/.."` implies publish-subscribe
10451064(__one-to-many__) and `"/queue/"` implies point-to-point (__one-to-one__) message
10461065exchanges.
1047- ==== 
10481066
10491067STOMP servers can use the +MESSAGE+ command to broadcast messages to all subscribers.
10501068Here is an example of a server sending a stock quote to a subscribed client:
@@ -1058,26 +1076,21 @@ destination:/topic/price.stock.MMM
10581076{"ticker":"MMM","price":129.45}^@ 
10591077---- 
10601078
1061- [NOTE]
1062- ==== 
10631079It is important to know that a server cannot send unsolicited messages. All messages
10641080from a server must be in response to a specific client subscription, and the
10651081+"subscription-id"+ header of the server message must match the +"id"+ header of the
10661082client subscription.
1067- ==== 
10681083
10691084The above overview is intended to provide the most basic understanding of the
10701085STOMP protocol. It is recommended to review the protocol
1071- http://stomp.github.io/stomp-specification-1.2.html[specification], which is
1072- easy to follow and manageable in terms of size.
1086+ http://stomp.github.io/stomp-specification-1.2.html[specification] in full.
10731087
1074- The following summarizes the  benefits for an application  of using STOMP over  WebSocket:
1088+ The benefits of using STOMP as a  WebSocket sub-protocol :
10751089
1076- * Standard message format
1077- * Application-level protocol with support for common messaging patterns
1078- * Client-side support, e.g. https://github.com/jmesnil/stomp-websocket[stomp.js], https://github.com/cujojs/msgs[msgs.js]
1079- * The ability to interpret, route, and process messages on both the client and server-side
1080- * The option to plug in a message broker -- RabbitMQ, ActiveMQ, many others -- to broadcast messages (explained later)
1090+ * No need to invent a custom message format
1091+ * Use existing https://github.com/jmesnil/stomp-websocket[stomp.js] client in the browser
1092+ * Ability to route messages to based on destination
1093+ * Option to use full-fledged message broker such as RabbitMQ, ActiveMQ, etc. for broadcasting
10811094
10821095Most importantly the use of STOMP (vs plain WebSocket) enables the Spring Framework
10831096to provide a programming model for application-level use in the same way that
@@ -1088,10 +1101,12 @@ Spring MVC provides a programming model based on HTTP.
10881101[[websocket-stomp-enable]]
10891102=== Enable STOMP over WebSocket
10901103The Spring Framework provides support for using STOMP over WebSocket through
1091- the +spring-messaging+ and +spring-websocket+ modules. It's easy to enable it.
1092- 
1093- Here is an example of configuring a STOMP WebSocket endpoint with SockJS fallback
1094- options. The endpoint is available for clients to connect to a URL path `/portfolio`:
1104+ the +spring-messaging+ and +spring-websocket+ modules.
1105+ Here is an example of exposing a STOMP WebSocket/SockJS endpoint at the URL path
1106+ `/portfolio` where messages whose destination starts with "/app" are routed to
1107+ message-handling methods (i.e. application work) and messages whose destinations
1108+ start with "/topic" or "/queue" will be routed to the message broker (i.e.
1109+ broadcasting to other connected clients):
10951110
10961111[source,java,indent=0]
10971112[subs="verbatim,quotes"]
@@ -1103,23 +1118,21 @@ options. The endpoint is available for clients to connect to a URL path `/portfo
11031118	@EnableWebSocketMessageBroker 
11041119	public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { 
11051120
1106- 		@Override 
1107-         public void configureMessageBroker(MessageBrokerRegistry config) { 
1108-             config.setApplicationDestinationPrefixes("/app"); 
1109-             config.enableSimpleBroker("/queue", "/topic"); 
1110-         } 
1111- 
11121121		@Override 
11131122		public void registerStompEndpoints(StompEndpointRegistry registry) { 
11141123			registry.addEndpoint("/portfolio").withSockJS(); 
11151124		} 
11161125
1117- 		// ... 
1126+ 		@Override 
1127+         public void configureMessageBroker(MessageBrokerRegistry config) { 
1128+             config.setApplicationDestinationPrefixes("/app"); 
1129+             config.enableSimpleBroker("/topic", "/queue"); 
1130+         } 
11181131
11191132	} 
11201133---- 
11211134
1122- XML configuration equivalent :
1135+ and in XML :
11231136
11241137[source,xml,indent=0]
11251138[subs="verbatim,quotes,attributes"]
@@ -1137,13 +1150,29 @@ XML configuration equivalent:
11371150			<websocket:stomp-endpoint path="/portfolio"> 
11381151				<websocket:sockjs/> 
11391152			</websocket:stomp-endpoint> 
1140- 			<websocket:simple-broker prefix="/queue, /topic"/> 
1141- 			... 
1153+ 			<websocket:simple-broker prefix="/topic, /queue"/> 
11421154		</websocket:message-broker> 
11431155
11441156	</beans> 
11451157---- 
11461158
1159+ [NOTE]
1160+ ==== 
1161+ The "/app" prefix is arbitrary. You can pick any prefix. It's simply meant to differentiate 
1162+ messages to be routed to message-handling methods to do application work vs messages 
1163+ to be routed to the broker to broadcast to subscribed clients. 
1164+ 
1165+ The "/topic" and "/queue" prefixes depend on the broker in use. In the case of the simple, 
1166+ in-memory broker the prefixes do not have any special meaning; it's merely a convention 
1167+ that indicates how the destination is used (pub-sub targetting many subscribers or 
1168+ point-to-point messages typically targeting an individual recipient). 
1169+ In the case of using a dedicated broker, most brokers use "/topic" as 
1170+ a prefix for destinations with pub-sub semantics and "/queue" for destinations 
1171+ with point-to-point semantics. Check the STOMP page of the broker to see the destination 
1172+ semantics it supports. 
1173+ ==== 
1174+ 
1175+ 
11471176On the browser side, a client might connect as follows using
11481177https://github.com/jmesnil/stomp-websocket[stomp.js] and the
11491178https://github.com/sockjs/sockjs-client[sockjs-client]:
@@ -1180,10 +1209,11 @@ sections <<websocket-stomp-handle-broker-relay-configure>> and
11801209=== Flow of Messages
11811210
11821211When a STOMP endpoint is configured, the Spring application acts as the STOMP broker
1183- to connected clients. It handles incoming messages and sends  messages back. 
1184- This section provides a big picture overview of how messages flow inside  the application.
1212+ to connected clients. This section provides a big picture overview of how  messages flow 
1213+ within  the application.
11851214
1186- The `spring-messaging` module contains a number of abstractions that originated in the
1215+ The `spring-messaging` module provides the foundation for asynchronous message processing.
1216+ It contains a number of abstractions that originated in the
11871217https://spring.io/spring-integration[Spring Integration] project and are intended
11881218for use as building blocks in messaging applications:
11891219
@@ -1199,16 +1229,22 @@ extends `MessageChannel` and sends messages to registered `MessageHandler` subsc
11991229a concrete implementation of `SubscribableChannel` that can deliver messages
12001230asynchronously via a thread pool.
12011231
1202- The provided STOMP over WebSocket config, both Java and XML, uses the above to
1203- assemble a concrete message flow including the following 3 channels:
1232+ The `@EnableWebSocketMessageBroker` Java config and the `<websocket:message-broker>` XML config
1233+ both assemble a concrete message flow. Below is a diagram of the part of the setup when using
1234+ the simple, in-memory broker:
1235+ 
1236+ image::images/message-flow-simple-broker.png[width=640]
1237+ 
1238+ The above setup that includes 3 message channels:
1239+ 
1240+ * `"clientInboundChannel"` for messages from WebSocket clients.
1241+ * `"clientOutboundChannel"` for messages to WebSocket clients.
1242+ * `"brokerChannel"` for messages to the broker from within the application.
1243+ 
1244+ The same three channels are also used with a dedicated broker except here a
1245+ "broker relay" takes the place of the simple broker:
12041246
1205- * `"clientInboundChannel"` -- for messages from WebSocket clients. Every incoming
1206- WebSocket message carrying a STOMP frame is sent through this channel.
1207- * `"clientOutboundChannel"` -- for messages to WebSocket clients. Every outgoing
1208- STOMP message from the broker is sent through this channel before getting sent
1209- to a client's WebSocket session.
1210- * `"brokerChannel"` -- for messages to the broker from within the application.
1211- Every message sent from the application to the broker passes through this channel.
1247+ image::images/message-flow-broker-relay.png[width=640]
12121248
12131249Messages on the `"clientInboundChannel"` can flow to annotated
12141250methods for application handling (e.g. a stock trade execution request) or can
0 commit comments