Update docs on @SendTo and @SendToUser
1. Explain that both can be used on the same method 2. Better describe semantics for class vs method level 3. General improvements Issue: SPR-16336
This commit is contained in:
@@ -32,9 +32,8 @@ import org.springframework.messaging.Message;
|
|||||||
* convey the destination to use for the reply. In that case, that destination
|
* convey the destination to use for the reply. In that case, that destination
|
||||||
* should take precedence.
|
* should take precedence.
|
||||||
*
|
*
|
||||||
* <p>The annotation may also be placed at class-level if the provider supports
|
* <p>This annotation may be placed class-level in which case it is inherited by
|
||||||
* it to indicate that all related methods should use this destination if none
|
* methods of the class.
|
||||||
* is specified otherwise.
|
|
||||||
*
|
*
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -25,13 +25,17 @@ import java.lang.annotation.Target;
|
|||||||
import org.springframework.core.annotation.AliasFor;
|
import org.springframework.core.annotation.AliasFor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Annotation that indicates that the return value of a message-handling method
|
* Indicates the return value of a message-handling method should be sent as a
|
||||||
* should be sent as a {@link org.springframework.messaging.Message} to the specified
|
* {@link org.springframework.messaging.Message} to the specified destination(s)
|
||||||
* destination(s) prepended with <code>"/user/{username}"</code> where the user name
|
* further prepended with <code>"/user/{username}"</code> where the user name
|
||||||
* is extracted from the headers of the input message being handled.
|
* is extracted from the headers of the input message being handled.
|
||||||
*
|
*
|
||||||
* <p>The annotation may also be placed at class-level in which case all methods
|
* <p>Both {@code @SendTo} and {@code @SendToUser} may be used on the same method
|
||||||
* in the class where the annotation applies will inherit it.
|
* in which case a message is sent to the destinations of both annotations.
|
||||||
|
*
|
||||||
|
* <p>This annotation may be placed class-level in which case it is inherited
|
||||||
|
* by methods of the class. At the same time, method-level {@code @SendTo} or
|
||||||
|
* {@code @SendToUser} annotations override any such at the class level.
|
||||||
|
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
|
|||||||
@@ -330,15 +330,14 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
|||||||
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
|
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
|
||||||
|
|
||||||
// Single-purpose return value types
|
// Single-purpose return value types
|
||||||
|
|
||||||
handlers.add(new ListenableFutureReturnValueHandler());
|
handlers.add(new ListenableFutureReturnValueHandler());
|
||||||
handlers.add(new CompletableFutureReturnValueHandler());
|
handlers.add(new CompletableFutureReturnValueHandler());
|
||||||
|
|
||||||
// Annotation-based return value types
|
// Annotation-based return value types
|
||||||
SendToMethodReturnValueHandler sendToHandler =
|
|
||||||
new SendToMethodReturnValueHandler(this.brokerTemplate, true);
|
SendToMethodReturnValueHandler sendToHandler = new SendToMethodReturnValueHandler(this.brokerTemplate, true);
|
||||||
if (this.headerInitializer != null) {
|
sendToHandler.setHeaderInitializer(this.headerInitializer);
|
||||||
sendToHandler.setHeaderInitializer(this.headerInitializer);
|
|
||||||
}
|
|
||||||
handlers.add(sendToHandler);
|
handlers.add(sendToHandler);
|
||||||
|
|
||||||
SubscriptionMethodReturnValueHandler subscriptionHandler =
|
SubscriptionMethodReturnValueHandler subscriptionHandler =
|
||||||
@@ -350,6 +349,7 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
|||||||
handlers.addAll(getCustomReturnValueHandlers());
|
handlers.addAll(getCustomReturnValueHandlers());
|
||||||
|
|
||||||
// catch-all
|
// catch-all
|
||||||
|
|
||||||
sendToHandler = new SendToMethodReturnValueHandler(this.brokerTemplate, false);
|
sendToHandler = new SendToMethodReturnValueHandler(this.brokerTemplate, false);
|
||||||
sendToHandler.setHeaderInitializer(this.headerInitializer);
|
sendToHandler.setHeaderInitializer(this.headerInitializer);
|
||||||
handlers.add(sendToHandler);
|
handlers.add(sendToHandler);
|
||||||
|
|||||||
@@ -1214,22 +1214,17 @@ methods as described next.
|
|||||||
[[websocket-stomp-message-mapping]]
|
[[websocket-stomp-message-mapping]]
|
||||||
==== `@MessageMapping`
|
==== `@MessageMapping`
|
||||||
|
|
||||||
The `@MessageMapping` annotation can be used on methods to route messages based on their
|
`@MessageMapping` can be used to annotate methods to route messages based on their
|
||||||
destination. It is supported at the method level as well as at the type level. At type
|
destination. It is supported at the method level as well as at the type level. At type
|
||||||
level `@MessageMapping` is used to express shared mappings across all methods in a
|
level `@MessageMapping` is used to express shared mappings across all methods in a
|
||||||
controller.
|
controller.
|
||||||
|
|
||||||
By default destination mappings are expected to be Ant-style, path patterns, e.g. "/foo*",
|
The mapping values are Ant-style path patterns by default, e.g. "/foo*", "/foo/**"
|
||||||
"/foo/**". The patterns include support for template variables, e.g. "/foo/{id}", that can
|
including support for template variables, e.g. "/foo/{id}", that can be referenced via
|
||||||
be referenced with `@DestinationVariable` method arguments.
|
`@DestinationVariable` method arguments. Applications can also switch to a dot-separated
|
||||||
|
destination convention for mappings, as explained in <<websocket-stomp-destination-separator>>.
|
||||||
|
|
||||||
[TIP]
|
*Supported Method Arguments*
|
||||||
====
|
|
||||||
Applications can choose to switch to a dot-separated destination convention.
|
|
||||||
See <<websocket-stomp-destination-separator>>.
|
|
||||||
====
|
|
||||||
|
|
||||||
`@MessageMapping` methods can have flexible signatures with the following arguments:
|
|
||||||
|
|
||||||
[cols="1,2", options="header"]
|
[cols="1,2", options="header"]
|
||||||
|===
|
|===
|
||||||
@@ -1271,47 +1266,52 @@ Values will be converted to the declared method argument type as necessary.
|
|||||||
|
|
||||||
|===
|
|===
|
||||||
|
|
||||||
When an `@MessageMapping` method returns a value, by default the value is serialized to
|
*Return Values*
|
||||||
a payload through a configured `MessageConverter`, and then sent as a `Message` to the
|
|
||||||
`"brokerChannel"` from where it is broadcast to subscribers. The destination of the
|
|
||||||
outbound message is the same as that of the inbound message but prefixed with `"/topic"`.
|
|
||||||
|
|
||||||
You can use the `@SendTo` method annotation to customize the destination to send
|
By default, the return value from an `@MessageMapping` method is serialized to a payload
|
||||||
the payload to. `@SendTo` can also be used at the class level to share a default target
|
through a matching `MessageConverter`, and sent as a `Message` to the `"brokerChannel"`
|
||||||
destination to send messages to. `@SendToUser` is an variant for sending messages only to
|
from where it is broadcast to subscribers. The destination of the outbound message is the
|
||||||
the user associated with a message. See <<websocket-stomp-user-destination>> for details.
|
same as that of the inbound message but prefixed with `"/topic"`.
|
||||||
|
|
||||||
The return value from an `@MessageMapping` method may be wrapped with `ListenableFuture`,
|
The `@SendTo` and `@SendToUser` annotations can be used to customize the destination of
|
||||||
`CompletableFuture`, or `CompletionStage` in order to produce the payload asynchronously.
|
the output message. `@SendTo` is used to simply customize target destination, or to
|
||||||
|
specify multiple destinations. `@SendToUser` is used to direct the output message only
|
||||||
|
to the user associated with the input message, see <<websocket-stomp-user-destination>>.
|
||||||
|
|
||||||
As an alternative to returning a payload from an `@MessageMapping` method you can also
|
`@SendTo` and `@SendToUser` may both be used at the same time on the same method, and both
|
||||||
send messages using the `SimpMessagingTemplate`, which is also how return values are
|
are supported at the class level in which case they act as a default for methods in the
|
||||||
handled under the covers. See <<websocket-stomp-handle-send>>.
|
class. However keep in mind that _any_ method-level `@SendTo` or `@SendToUser` annotations
|
||||||
|
override _any_ such annotations at the class level.
|
||||||
|
|
||||||
|
Messages may be handled asynchronously and a `@MessageMapping` method may return
|
||||||
|
`ListenableFuture`, `CompletableFuture`, or `CompletionStage`.
|
||||||
|
|
||||||
|
Note that `@SendTo` and `@SendToUser` are merely a convenience that amounts to using the
|
||||||
|
`SimpMessagingTemplate` to send messages. If necessary, for more advanced scenarios,
|
||||||
|
`@MessageMapping` methods can fall back on using the `SimpMessagingTemplate` directly.
|
||||||
|
This can be done instead of, or possibly in addition to returning a value.
|
||||||
|
See <<websocket-stomp-handle-send>>.
|
||||||
|
|
||||||
|
|
||||||
[[websocket-stomp-subscribe-mapping]]
|
[[websocket-stomp-subscribe-mapping]]
|
||||||
==== `@SubscribeMapping`
|
==== `@SubscribeMapping`
|
||||||
|
|
||||||
The `@SubscribeMapping` annotation is used in combination with `@MessageMapping` in order
|
`@SubscribeMapping` is used together with `@MessageMapping` to narrow the mapping to
|
||||||
to narrow the mapping to subscription messages. In such scenarios, the `@MessageMapping`
|
subscription messages. In this scenario `@MessageMapping` expresses message destination
|
||||||
annotation specifies the destination while `@SubscribeMapping` indicates interest in
|
mappings for routing purposes, which can be done at the class or at the method level,
|
||||||
subscription messages only.
|
while `@SubscribeMapping` narrows the mapping to subscription messages only.
|
||||||
|
|
||||||
An `@SubscribeMapping` method is generally no different from any `@MessageMapping`
|
Methods with `@MessageMapping` and `@SubscribeMapping` support the same
|
||||||
method with respect to mapping and input arguments. For example you can combine it with a
|
<<websocket-stomp-message-mapping,method arguments>> as methods annotated only with
|
||||||
type-level `@MessageMapping` to express a shared destination prefix, and you can use the
|
`@MessageMapping` do. However for the return value, in the absence of `@SendTo` and
|
||||||
same <<websocket-stomp-message-mapping,method arguments>> as any @MessageMapping` method.
|
`@SendToUser`, a message is sent directly as a reply to the subscription, via the
|
||||||
|
"clientOutboundChannel" channel. Effectively the subscription is used as a one-time,
|
||||||
|
request-reply message exchange with the subscription never stored. This is useful for
|
||||||
|
loading data on startup and for initializing a front-end UI.
|
||||||
|
|
||||||
The key difference with `@SubscribeMapping` is that the return value of the method is
|
If an `@SubscribeMapping` method is annotated with `@SendTo` and `@SendToUser` the return
|
||||||
serialized as a payload and sent, not to the "brokerChannel" but to the
|
value is sent to the `"brokerChannel"` as usual, sending a message subscribers of the
|
||||||
"clientOutboundChannel", effectively replying directly to the client rather than
|
specified destination(s).
|
||||||
broadcasting through the broker. This is useful for implementing one-off, request-reply
|
|
||||||
message exchanges, and never holding on to the subscription. A common scenario for this
|
|
||||||
pattern is application initialization when data must be loaded and presented.
|
|
||||||
|
|
||||||
A `@SubscribeMapping` method can also be annotated with `@SendTo` in which case the
|
|
||||||
return value is sent to the `"brokerChannel"` with the explicitly specified target
|
|
||||||
destination.
|
|
||||||
|
|
||||||
|
|
||||||
[[websocket-stomp-exception-handler]]
|
[[websocket-stomp-exception-handler]]
|
||||||
|
|||||||
Reference in New Issue
Block a user