Doc use of reactive types in Spring MVC controllers

Issue: SPR-15365
This commit is contained in:
Rossen Stoyanchev 2017-04-04 17:32:24 -04:00
parent f716c8e9bc
commit f293c4d84b
4 changed files with 111 additions and 59 deletions

View File

@ -34,7 +34,7 @@ import org.springframework.core.annotation.AliasFor;
* types, in arbitrary order (except for validation results, which need to
* follow right after the corresponding command object, if desired):
* <ul>
* <li>Request and/or response objects (typically from the Servlet API).
* <li>Request and/or response objects from the Servlet API.
* You may choose any specific request/response type, e.g.
* {@link javax.servlet.ServletRequest} / {@link javax.servlet.http.HttpServletRequest}.
* <li>Session object: typically {@link javax.servlet.http.HttpSession}.
@ -60,7 +60,7 @@ import org.springframework.core.annotation.AliasFor;
* the response's content. This will be the raw OutputStream/Writer as
* exposed by the Servlet API.
* <li>{@link org.springframework.http.HttpMethod} for the HTTP request method</li>
* <li>{@link PathVariable @PathVariable} annotated parameters (Servlet-only)
* <li>{@link PathVariable @PathVariable} annotated parameters
* for access to URI template values (i.e. /hotels/{hotel}). Variable values will be
* converted to the declared method argument type. By default, the URI template
* will match against the regular expression {@code [^\.]*} (i.e. any character
@ -69,7 +69,7 @@ import org.springframework.core.annotation.AliasFor;
* Additionally, {@code @PathVariable} can be used on a
* {@link java.util.Map Map&lt;String, String&gt;} to gain access to all
* URI template variables.
* <li>{@link MatrixVariable @MatrixVariable} annotated parameters (Servlet-only)
* <li>{@link MatrixVariable @MatrixVariable} annotated parameters
* for access to name-value pairs located in URI path segments. Matrix variables
* must be represented with a URI template variable. For example /hotels/{hotel}
* where the incoming URL may be "/hotels/42;q=1".
@ -89,7 +89,7 @@ import org.springframework.core.annotation.AliasFor;
* {@link org.springframework.util.MultiValueMap MultiValueMap&lt;String, String&gt;}, or
* {@link org.springframework.http.HttpHeaders HttpHeaders} method parameter to
* gain access to all request headers.
* <li>{@link RequestBody @RequestBody} annotated parameters (Servlet-only)
* <li>{@link RequestBody @RequestBody} annotated parameters
* for access to the Servlet request HTTP contents. The request stream will be
* converted to the declared method argument type using
* {@linkplain org.springframework.http.converter.HttpMessageConverter message
@ -98,9 +98,7 @@ import org.springframework.core.annotation.AliasFor;
* {@link org.springframework.validation.Errors} argument.
* Instead a {@link org.springframework.web.bind.MethodArgumentNotValidException}
* exception is raised.
* <li>{@link RequestPart @RequestPart} annotated parameters
* (Servlet-only, {@literal @MVC 3.1-only})
* for access to the content
* <li>{@link RequestPart @RequestPart} annotated parameters for access to the content
* of a part of "multipart/form-data" request. The request part stream will be
* converted to the declared method argument type using
* {@linkplain org.springframework.http.converter.HttpMessageConverter message
@ -116,15 +114,15 @@ import org.springframework.core.annotation.AliasFor;
* <li>{@link RequestAttribute @RequestAttribute} annotated parameters for access
* to request attributes.
* <li>{@link org.springframework.http.HttpEntity HttpEntity&lt;?&gt;} parameters
* (Servlet-only) for access to the Servlet request HTTP headers and contents.
* for access to the Servlet request HTTP headers and contents.
* The request stream will be converted to the entity body using
* {@linkplain org.springframework.http.converter.HttpMessageConverter message
* converters}.
* <li>{@link java.util.Map} / {@link org.springframework.ui.Model} /
* {@link org.springframework.ui.ModelMap} for enriching the implicit model
* that will be exposed to the web view.
* <li>{@link org.springframework.web.servlet.mvc.support.RedirectAttributes}
* (Servlet-only, {@literal @MVC 3.1-only}) to specify the exact set of attributes
* <li>{@link org.springframework.web.servlet.mvc.support.RedirectAttributes},
* to specify the exact set of attributes
* to use in case of a redirect and also to add flash attributes (attributes
* stored temporarily on the server-side to make them available to the request
* after the redirect). {@code RedirectAttributes} is used instead of the
@ -147,7 +145,6 @@ import org.springframework.core.annotation.AliasFor;
* attributes that have been indicated by the {@link SessionAttributes @SessionAttributes}
* annotation at the handler type level).
* <li>{@link org.springframework.web.util.UriComponentsBuilder}
* (Servlet-only, {@literal @MVC 3.1-only})
* for preparing a URL relative to the current request's host, port, scheme,
* context path, and the literal part of the servlet mapping.
* </ul>
@ -160,64 +157,63 @@ import org.springframework.core.annotation.AliasFor;
*
* <p>The following return types are supported for handler methods:
* <ul>
* <li>A {@code ModelAndView} object (from Servlet MVC),
* <li>{@code ModelAndView} object (from Servlet MVC),
* with the model implicitly enriched with command objects and the results
* of {@link ModelAttribute @ModelAttribute} annotated reference data accessor methods.
* <li>A {@link org.springframework.ui.Model Model} object, with the view name implicitly
* <li>{@link org.springframework.ui.Model Model} object, with the view name implicitly
* determined through a {@link org.springframework.web.servlet.RequestToViewNameTranslator}
* and the model implicitly enriched with command objects and the results
* of {@link ModelAttribute @ModelAttribute} annotated reference data accessor methods.
* <li>A {@link java.util.Map} object for exposing a model,
* <li>{@link java.util.Map} object for exposing a model,
* with the view name implicitly determined through a
* {@link org.springframework.web.servlet.RequestToViewNameTranslator}
* and the model implicitly enriched with command objects and the results
* of {@link ModelAttribute @ModelAttribute} annotated reference data accessor methods.
* <li>A {@link org.springframework.web.servlet.View} object, with the
* <li>{@link org.springframework.web.servlet.View} object, with the
* model implicitly determined through command objects and
* {@link ModelAttribute @ModelAttribute} annotated reference data accessor methods.
* The handler method may also programmatically enrich the model by
* declaring a {@link org.springframework.ui.Model} argument (see above).
* <li>A {@link String} value which is interpreted as view name,
* <li>{@link String} value which is interpreted as view name,
* with the model implicitly determined through command objects and
* {@link ModelAttribute @ModelAttribute} annotated reference data accessor methods.
* The handler method may also programmatically enrich the model by
* declaring a {@link org.springframework.ui.ModelMap} argument
* (see above).
* <li>{@link ResponseBody @ResponseBody} annotated methods (Servlet-only)
* <li>{@link ResponseBody @ResponseBody} annotated methods
* for access to the Servlet response HTTP contents. The return value will
* be converted to the response stream using
* {@linkplain org.springframework.http.converter.HttpMessageConverter message
* converters}.
* <li>An {@link org.springframework.http.HttpEntity HttpEntity&lt;?&gt;} or
* <li>{@link org.springframework.http.HttpEntity HttpEntity&lt;?&gt;} or
* {@link org.springframework.http.ResponseEntity ResponseEntity&lt;?&gt;} object
* (Servlet-only) to access to the Servlet response HTTP headers and contents.
* to access to the Servlet response HTTP headers and contents.
* The entity body will be converted to the response stream using
* {@linkplain org.springframework.http.converter.HttpMessageConverter message
* converters}.
* <li>An {@link org.springframework.http.HttpHeaders HttpHeaders} object to
* <li>{@link org.springframework.http.HttpHeaders HttpHeaders} object to
* return a response with no body.</li>
* <li>A {@link Callable} which is used by Spring MVC to obtain the return
* value asynchronously in a separate thread transparently managed by Spring MVC
* on behalf of the application.
* <li>A {@link org.springframework.web.context.request.async.DeferredResult}
* which the application uses to produce a return value in a separate
* thread of its own choosing, as an alternative to returning a Callable.
* <li>A {@link org.springframework.util.concurrent.ListenableFuture}
* which the application uses to produce a return value in a separate
* thread of its own choosing, as an alternative to returning a Callable.
* <li>A {@link java.util.concurrent.CompletionStage} (implemented by
* {@link java.util.concurrent.CompletableFuture} for example)
* which the application uses to produce a return value in a separate
* thread of its own choosing, as an alternative to returning a Callable.
* <li>A {@link org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter}
* can be used to write multiple objects to the response asynchronously;
* also supported as the body within {@code ResponseEntity}.</li>
* <li>An {@link org.springframework.web.servlet.mvc.method.annotation.SseEmitter}
* can be used to write Server-Sent Events to the response asynchronously;
* also supported as the body within {@code ResponseEntity}.</li>
* <li>A {@link org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody}
* can be used to write to the response asynchronously;
* also supported as the body within {@code ResponseEntity}.</li>
* <li>{@link Callable} -- async computation in a Spring MVC managed thread.</li>
* <li>{@link org.springframework.web.context.request.async.DeferredResult DeferredResult} --
* async result produced later from an application managed, or any thread.
* <li>{@link org.springframework.util.concurrent.ListenableFuture ListenableFuture}
* alternative, equivalent to {@code DeferredResult}.</li>
* <li>{@link java.util.concurrent.CompletionStage CompletionStage} and
* {@link java.util.concurrent.CompletableFuture CompletableFuture} --
* alternative, equivalent to {@code DeferredResult}.</li>
* <li>{@link org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter} --
* {@code @ResponseBody}-style, asynchronous writing of a stream of Objects to the
* response body.</li>
* <li>{@link org.springframework.web.servlet.mvc.method.annotation.SseEmitter} --
* variant of {@code ResponseBodyEmitter} for a Server-Sent Events formatted stream.</li>
* <li>{@link org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody} --
* async writing directly to the response body {@link java.io.OutputStream}.</li>
* <li>Reactive types (e.g. Reactor {@code Flux}/{@code Mono}, RxJava 1 &amp; 2
* {@code Observable}/{@code Single}, or others via
* {@link org.springframework.core.ReactiveAdapterRegistry ReactiveAdapterRegistry}) --
* alternatives, equivalent to {@code DeferredResult} or {@code ResponseBodyEmitter}
* and {@code SseEmitter} depending also on the requested media types (e.g.
* "text/event-stream", "application/json+stream").</li>
* <li>{@code void} if the method handles the response itself (by
* writing the response content directly, declaring an argument of type
* {@link javax.servlet.ServletResponse} / {@link javax.servlet.http.HttpServletResponse}

View File

@ -56,6 +56,11 @@ public class AsyncSupportConfigurer {
* highly recommended to change that default in production since the simple
* executor does not re-use threads.
*
* <p>As of 5.0 this executor is also used when a controller returns a reactive
* type that does streaming (e.g. "text/event-stream" or
* "application/stream+json") for the blocking writes to the
* {@link javax.servlet.ServletOutputStream}.
*
* @param taskExecutor the task executor instance to use by default
*/
public AsyncSupportConfigurer setTaskExecutor(AsyncTaskExecutor taskExecutor) {

View File

@ -231,9 +231,14 @@
<xsd:attribute name="task-executor" type="xsd:string">
<xsd:annotation>
<xsd:documentation source="java:org.springframework.core.task.AsyncTaskExecutor"><![CDATA[
The bean name of a default AsyncTaskExecutor to use when a controller method returns a {@link Callable}.
The bean name of a default AsyncTaskExecutor to use when a controller method returns a "Callable".
Controller methods can override this default on a per-request basis by returning an AsyncTask.
By default, a SimpleAsyncTaskExecutor is used which does not re-use threads and is not recommended for production.
As of 5.0 this executor is also used when a controller returns a reactive type that does streaming
(e.g. "text/event-stream" or "application/stream+json") for the blocking writes to the
"javax.servlet.ServletOutputStream".
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">

View File

@ -1408,18 +1408,18 @@ of `java.util.Optional` in those cases is equivalent to having `required=false`.
==== Supported method return types
The following are the supported return types:
* A `ModelAndView` object, with the model implicitly enriched with command objects and
* `ModelAndView` object, with the model implicitly enriched with command objects and
the results of `@ModelAttribute` annotated reference data accessor methods.
* A `Model` object, with the view name implicitly determined through a
* `Model` object, with the view name implicitly determined through a
`RequestToViewNameTranslator` and the model implicitly enriched with command objects
and the results of `@ModelAttribute` annotated reference data accessor methods.
* A `Map` object for exposing a model, with the view name implicitly determined through
* `Map` object for exposing a model, with the view name implicitly determined through
a `RequestToViewNameTranslator` and the model implicitly enriched with command objects
and the results of `@ModelAttribute` annotated reference data accessor methods.
* A `View` object, with the model implicitly determined through command objects and
* `View` object, with the model implicitly determined through command objects and
`@ModelAttribute` annotated reference data accessor methods. The handler method may
also programmatically enrich the model by declaring a `Model` argument (see above).
* A `String` value that is interpreted as the logical view name, with the model
* `String` value that is interpreted as the logical view name, with the model
implicitly determined through command objects and `@ModelAttribute` annotated
reference data accessor methods. The handler method may also programmatically enrich
the model by declaring a `Model` argument (see above).
@ -1431,22 +1431,25 @@ The following are the supported return types:
* If the method is annotated with `@ResponseBody`, the return type is written to the
response HTTP body. The return value will be converted to the declared method argument
type using ``HttpMessageConverter``s. See <<mvc-ann-responsebody>>.
* An `HttpEntity<?>` or `ResponseEntity<?>` object to provide access to the Servlet
* `HttpEntity<?>` or `ResponseEntity<?>` object to provide access to the Servlet
response HTTP headers and contents. The entity body will be converted to the response
stream using ``HttpMessageConverter``s. See <<mvc-ann-httpentity>>.
* An `HttpHeaders` object to return a response with no body.
* A `Callable<?>` can be returned when the application wants to produce the return value
asynchronously in a thread managed by Spring MVC.
* A `DeferredResult<?>` can be returned when the application wants to produce the return
value from a thread of its own choosing.
* A `ListenableFuture<?>` or `CompletableFuture<?>`/`CompletionStage<?>` can be returned
when the application wants to produce the value from a thread pool submission.
* A `ResponseBodyEmitter` can be returned to write multiple objects to the response
* `HttpHeaders` object to return a response with no body.
* `Callable<?>` async computation in a Spring MVC managed thread.
* `DeferredResult<?>` async result produced later from an application managed, or any thread.
* `ListenableFuture<?>` as an alternative equivalent to using `DeferredResult`.
* `CompletableFuture<?>` or `CompletionStage<?>` as an alternative equivalent to `DeferredResult`.
* `ResponseBodyEmitter` can be returned to write multiple objects to the response
asynchronously; also supported as the body within a `ResponseEntity`.
* An `SseEmitter` can be returned to write Server-Sent Events to the response
* `SseEmitter` can be returned to write Server-Sent Events to the response
asynchronously; also supported as the body within a `ResponseEntity`.
* A `StreamingResponseBody` can be returned to write to the response OutputStream
* `StreamingResponseBody` can be returned to write to the response OutputStream
asynchronously; also supported as the body within a `ResponseEntity`.
* Reactive types from Reactor 3, RxJava 2, RxJava 1 or others registered through
the configured `ReactiveAdapterRegistry` can be returned as an alternative
equivalent to using `DeferredResult` for single-valued types, or
`ResponseBodyEmitter` and `SseEmitter` for multi-valued reactive types where a streaming
media type (e.g. "text/event-stream", "application/json+stream") is requested.
* Any other return type is considered to be a single model attribute to be exposed to
the view, using the attribute name specified through `@ModelAttribute` at the method
level (or the default attribute name based on the return type class name). The model
@ -2517,6 +2520,49 @@ Note that `StreamingResponseBody` can also be used as the body in a
the response.
[[mvc-ann-async-reactive-types]]
==== Async Requests with Reactive Types
If using the reactive `WebClient` from `spring-webflux`, or another client, or
a data store with reactive support, you can return reactive types directly from
Spring MVC controller methods.
* If the return type has single-value stream semantics such as Reactor `Mono` or
RxJava `Single` it is adapted and equivalent to using `DeferredResult`.
* If the return type has multi-value stream semantics such as Reactor `Flux` or
RxJava `Observable` / `Flowable` and if the media type indicates streaming, e.g.
"application/stream+json" or "text/event-stream", it is adapted and equivalent to
using `ResponseBodyEmitter` or `SseEmitter`. You can also return
`Flux<ServerSentEvent>` or `Observable<ServerSentEvent>`.
* If the return type has multi-value stream semantics but the media type does not
imply streaming, e.g. "application/json", it is adapted and equivalent to using
`DeferredResult<List<?>>`, e.g. JSON array.
Reactive libraries are detected and adapted to a Reactive Streams `Publisher`
through Spring's pluggable `ReactiveAdapterRegistry` which by default supports
Reactor 3, RxJava 2, and RxJava 1. Note that for RxJava 1 you will need to add
https://github.com/ReactiveX/RxJavaReactiveStreams["io.reactivex:rxjava-reactive-streams"]
to the classpath.
A common assumption with reactive libraries is not block the processing thread.
The `WebClient` with Reactor Netty for example is based on event-loop style
handling using a small, fixed number of threads and those must not be blocked
when writing to the `ServletResponseOutputStream`. Reactive libraries have
operators for that but Spring MVC automatically writes asynchronously so you
don't need to use that. The underlying `TaskExecutor` for this can be configured
through the MVC Java config and the MVC namespace as described in the following
section.
[NOTE]
====
Unlike Spring MVC, Spring WebFlux is built on a non-blocking, reactive foundation
and uses the Servlet 3.1 non-blocking I/O that's also based on event loop style
processing and hence does not require a thread to absorb the effect of blocking.
====
[[mvc-ann-async-configuration]]
==== Configuring Asynchronous Request Processing