Spring Framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

258 lines
12 KiB

[[webflux-dispatcher-handler]]
= `DispatcherHandler`
[.small]#xref:web/webmvc/mvc-servlet.adoc[See equivalent in the Servlet stack]#
Spring WebFlux, similarly to Spring MVC, is designed around the front controller pattern,
where a central `WebHandler`, the `DispatcherHandler`, provides a shared algorithm for
request processing, while actual work is performed by configurable, delegate components.
This model is flexible and supports diverse workflows.
`DispatcherHandler` discovers the delegate components it needs from Spring configuration.
It is also designed to be a Spring bean itself and implements `ApplicationContextAware`
for access to the context in which it runs. If `DispatcherHandler` is declared with a bean
name of `webHandler`, it is, in turn, discovered by
{api-spring-framework}/web/server/adapter/WebHttpHandlerBuilder.html[`WebHttpHandlerBuilder`],
which puts together a request-processing chain, as described in xref:web/webflux/reactive-spring.adoc#webflux-web-handler-api[`WebHandler` API].
Spring configuration in a WebFlux application typically contains:
* `DispatcherHandler` with the bean name `webHandler`
* `WebFilter` and `WebExceptionHandler` beans
* xref:web/webflux/dispatcher-handler.adoc#webflux-special-bean-types[`DispatcherHandler` special beans]
* Others
The configuration is given to `WebHttpHandlerBuilder` to build the processing chain,
as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
ApplicationContext context = ...
HttpHandler handler = WebHttpHandlerBuilder.applicationContext(context).build();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
val context: ApplicationContext = ...
val handler = WebHttpHandlerBuilder.applicationContext(context).build()
----
======
The resulting `HttpHandler` is ready for use with a xref:web/webflux/reactive-spring.adoc#webflux-httphandler[server adapter].
[[webflux-special-bean-types]]
== Special Bean Types
[.small]#xref:web/webmvc/mvc-servlet/special-bean-types.adoc[See equivalent in the Servlet stack]#
The `DispatcherHandler` delegates to special beans to process requests and render the
appropriate responses. By "`special beans,`" we mean Spring-managed `Object` instances that
implement WebFlux framework contracts. Those usually come with built-in contracts, but
you can customize their properties, extend them, or replace them.
The following table lists the special beans detected by the `DispatcherHandler`. Note that
there are also some other beans detected at a lower level (see
xref:web/webflux/reactive-spring.adoc#webflux-web-handler-api-special-beans[Special bean types] in the Web Handler API).
[[webflux-special-beans-table]]
[cols="1,2", options="header"]
|===
| Bean type | Explanation
| `HandlerMapping`
| Map a request to a handler. The mapping is based on some criteria, the details of
which vary by `HandlerMapping` implementation -- annotated controllers, simple
URL pattern mappings, and others.
The main `HandlerMapping` implementations are `RequestMappingHandlerMapping` for
`@RequestMapping` annotated methods, `RouterFunctionMapping` for functional endpoint
routes, and `SimpleUrlHandlerMapping` for explicit registrations of URI path patterns
and `WebHandler` instances.
| `HandlerAdapter`
| Help the `DispatcherHandler` to invoke a handler mapped to a request regardless of
how the handler is actually invoked. For example, invoking an annotated controller
requires resolving annotations. The main purpose of a `HandlerAdapter` is to shield the
`DispatcherHandler` from such details.
| `HandlerResultHandler`
| Process the result from the handler invocation and finalize the response.
See xref:web/webflux/dispatcher-handler.adoc#webflux-resulthandling[Result Handling].
|===
[[webflux-framework-config]]
== WebFlux Config
[.small]#xref:web/webmvc/mvc-servlet/config.adoc[See equivalent in the Servlet stack]#
Applications can declare the infrastructure beans (listed under
xref:web/webflux/reactive-spring.adoc#webflux-web-handler-api-special-beans[Web Handler API] and
xref:web/webflux/dispatcher-handler.adoc#webflux-special-bean-types[`DispatcherHandler`]) that are required to process requests.
However, in most cases, the xref:web/webflux/dispatcher-handler.adoc#webflux-framework-config[WebFlux Config] is the best starting point. It declares the
required beans and provides a higher-level configuration callback API to customize it.
NOTE: Spring Boot relies on the WebFlux config to configure Spring WebFlux and also provides
many extra convenient options.
[[webflux-dispatcher-handler-sequence]]
== Processing
[.small]#xref:web/webmvc/mvc-servlet/sequence.adoc[See equivalent in the Servlet stack]#
`DispatcherHandler` processes requests as follows:
* Each `HandlerMapping` is asked to find a matching handler, and the first match is used.
* If a handler is found, it is run through an appropriate `HandlerAdapter`, which
exposes the return value from the execution as `HandlerResult`.
* The `HandlerResult` is given to an appropriate `HandlerResultHandler` to complete
processing by writing to the response directly or by using a view to render.
[[webflux-resulthandling]]
== Result Handling
The return value from the invocation of a handler, through a `HandlerAdapter`, is wrapped
as a `HandlerResult`, along with some additional context, and passed to the first
`HandlerResultHandler` that claims support for it. The following table shows the available
`HandlerResultHandler` implementations, all of which are declared in the xref:web/webflux/dispatcher-handler.adoc#webflux-framework-config[WebFlux Config]:
[cols="1,2,1", options="header"]
|===
| Result Handler Type | Return Values | Default Order
| `ResponseEntityResultHandler`
| `ResponseEntity`, typically from `@Controller` instances.
| 0
| `ServerResponseResultHandler`
| `ServerResponse`, typically from functional endpoints.
| 0
| `ResponseBodyResultHandler`
| Handle return values from `@ResponseBody` methods or `@RestController` classes.
| 100
| `ViewResolutionResultHandler`
| `CharSequence`, {api-spring-framework}/web/reactive/result/view/View.html[`View`],
{api-spring-framework}/ui/Model.html[Model], `Map`,
{api-spring-framework}/web/reactive/result/view/Rendering.html[Rendering],
or any other `Object` is treated as a model attribute.
See also xref:web/webflux/dispatcher-handler.adoc#webflux-viewresolution[View Resolution].
| `Integer.MAX_VALUE`
|===
[[webflux-dispatcher-exceptions]]
== Exceptions
[.small]#xref:web/webmvc/mvc-servlet/exceptionhandlers.adoc[See equivalent in the Servlet stack]#
`HandlerAdapter` implementations can handle internally exceptions from invoking a request
handler, such as a controller method. However, an exception may be deferred if the request
handler returns an asynchronous value.
A `HandlerAdapter` may expose its exception handling mechanism as a
`DispatchExceptionHandler` set on the `HandlerResult` it returns. When that's set,
`DispatcherHandler` will also apply it to the handling of the result.
A `HandlerAdapter` may also choose to implement `DispatchExceptionHandler`. In that case
`DispatcherHandler` will apply it to exceptions that arise before a handler is mapped,
e.g. during handler mapping, or earlier, e.g. in a `WebFilter`.
See also xref:web/webflux/controller/ann-exceptions.adoc[Exceptions] in the "`Annotated Controller`" section or
xref:web/webflux/reactive-spring.adoc#webflux-exception-handler[Exceptions] in the WebHandler API section.
[[webflux-viewresolution]]
== View Resolution
[.small]#xref:web/webmvc/mvc-servlet/viewresolver.adoc[See equivalent in the Servlet stack]#
View resolution enables rendering to a browser with an HTML template and a model without
tying you to a specific view technology. In Spring WebFlux, view resolution is
supported through a dedicated xref:web/webflux/dispatcher-handler.adoc#webflux-resulthandling[HandlerResultHandler] that uses
`ViewResolver` instances to map a String (representing a logical view name) to a `View`
instance. The `View` is then used to render the response.
[[webflux-viewresolution-handling]]
=== Handling
[.small]#xref:web/webmvc/mvc-servlet/viewresolver.adoc#mvc-viewresolver-handling[See equivalent in the Servlet stack]#
The `HandlerResult` passed into `ViewResolutionResultHandler` contains the return value
from the handler and the model that contains attributes added during request
handling. The return value is processed as one of the following:
* `String`, `CharSequence`: A logical view name to be resolved to a `View` through
the list of configured `ViewResolver` implementations.
* `void`: Select a default view name based on the request path, minus the leading and
trailing slash, and resolve it to a `View`. The same also happens when a view name
was not provided (for example, model attribute was returned) or an async return value
(for example, `Mono` completed empty).
* {api-spring-framework}/web/reactive/result/view/Rendering.html[Rendering]: API for
view resolution scenarios. Explore the options in your IDE with code completion.
* `Model`, `Map`: Extra model attributes to be added to the model for the request.
* Any other: Any other return value (except for simple types, as determined by
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty])
is treated as a model attribute to be added to the model. The attribute name is derived
from the class name by using {api-spring-framework}/core/Conventions.html[conventions],
unless a handler method `@ModelAttribute` annotation is present.
The model can contain asynchronous, reactive types (for example, from Reactor or RxJava). Prior
to rendering, `AbstractView` resolves such model attributes into concrete values
and updates the model. Single-value reactive types are resolved to a single
value or no value (if empty), while multi-value reactive types (for example, `Flux<T>`) are
collected and resolved to `List<T>`.
To configure view resolution is as simple as adding a `ViewResolutionResultHandler` bean
to your Spring configuration. xref:web/webflux/config.adoc#webflux-config-view-resolvers[WebFlux Config] provides a
dedicated configuration API for view resolution.
See xref:web/webflux-view.adoc[View Technologies] for more on the view technologies integrated with Spring WebFlux.
[[webflux-redirecting-redirect-prefix]]
=== Redirecting
[.small]#xref:web/webmvc/mvc-servlet/viewresolver.adoc#mvc-redirecting-redirect-prefix[See equivalent in the Servlet stack]#
The special `redirect:` prefix in a view name lets you perform a redirect. The
`UrlBasedViewResolver` (and sub-classes) recognize this as an instruction that a
redirect is needed. The rest of the view name is the redirect URL.
The net effect is the same as if the controller had returned a `RedirectView` or
`Rendering.redirectTo("abc").build()`, but now the controller itself can
operate in terms of logical view names. A view name such as
`redirect:/some/resource` is relative to the current application, while a view name such as
`redirect:https://example.com/arbitrary/path` redirects to an absolute URL.
[[webflux-multiple-representations]]
=== Content Negotiation
[.small]#xref:web/webmvc/mvc-servlet/viewresolver.adoc#mvc-multiple-representations[See equivalent in the Servlet stack]#
`ViewResolutionResultHandler` supports content negotiation. It compares the request
media types with the media types supported by each selected `View`. The first `View`
that supports the requested media type(s) is used.
In order to support media types such as JSON and XML, Spring WebFlux provides
`HttpMessageWriterView`, which is a special `View` that renders through an
xref:web/webflux/reactive-spring.adoc#webflux-codecs[HttpMessageWriter]. Typically, you would configure these as default
views through the xref:web/webflux/config.adoc#webflux-config-view-resolvers[WebFlux Configuration]. Default views are
always selected and used if they match the requested media type.