Scott Frederick 015dca1956 Remove support for Thymeleaf
Closes gh-28611
2021-11-30 15:55:47 +00:00

263 lines
12 KiB
Plaintext

[[web.reactive]]
== Reactive Web Applications
Spring Boot simplifies development of reactive web applications by providing auto-configuration for Spring Webflux.
[[web.reactive.webflux]]
=== The "`Spring WebFlux Framework`"
Spring WebFlux is the new reactive web framework introduced in Spring Framework 5.0.
Unlike Spring MVC, it does not require the servlet API, is fully asynchronous and non-blocking, and implements the https://www.reactive-streams.org/[Reactive Streams] specification through https://projectreactor.io/[the Reactor project].
Spring WebFlux comes in two flavors: functional and annotation-based.
The annotation-based one is quite close to the Spring MVC model, as shown in the following example:
[source,java,indent=0,subs="verbatim"]
----
include::{docs-java}/web/reactive/webflux/MyRestController.java[]
----
"`WebFlux.fn`", the functional variant, separates the routing configuration from the actual handling of the requests, as shown in the following example:
[source,java,indent=0,subs="verbatim"]
----
include::{docs-java}/web/reactive/webflux/MyRoutingConfiguration.java[]
----
[source,java,indent=0,subs="verbatim"]
----
include::{docs-java}/web/reactive/webflux/MyUserHandler.java[]
----
WebFlux is part of the Spring Framework and detailed information is available in its {spring-framework-docs}/web-reactive.html#webflux-fn[reference documentation].
TIP: You can define as many `RouterFunction` beans as you like to modularize the definition of the router.
Beans can be ordered if you need to apply a precedence.
To get started, add the `spring-boot-starter-webflux` module to your application.
NOTE: Adding both `spring-boot-starter-web` and `spring-boot-starter-webflux` modules in your application results in Spring Boot auto-configuring Spring MVC, not WebFlux.
This behavior has been chosen because many Spring developers add `spring-boot-starter-webflux` to their Spring MVC application to use the reactive `WebClient`.
You can still enforce your choice by setting the chosen application type to `SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE)`.
"`WebFlux.fn`", the functional variant, separates the routing configuration from the actual handling of the requests, as shown in the following example:
[source,java,indent=0,subs="verbatim"]
----
include::{docs-java}/web/reactive/webflux/MyRoutingConfiguration.java[]
----
[source,java,indent=0,subs="verbatim"]
----
include::{docs-java}/web/reactive/webflux/MyUserHandler.java[]
----
WebFlux is part of the Spring Framework and detailed information is available in its {spring-framework-docs}/web-reactive.html#webflux-fn[reference documentation].
TIP: You can define as many `RouterFunction` beans as you like to modularize the definition of the router.
Beans can be ordered if you need to apply a precedence.
To get started, add the `spring-boot-starter-webflux` module to your application.
NOTE: Adding both `spring-boot-starter-web` and `spring-boot-starter-webflux` modules in your application results in Spring Boot auto-configuring Spring MVC, not WebFlux.
This behavior has been chosen because many Spring developers add `spring-boot-starter-webflux` to their Spring MVC application to use the reactive `WebClient`.
You can still enforce your choice by setting the chosen application type to `SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE)`.
[[web.reactive.webflux.auto-configuration]]
==== Spring WebFlux Auto-configuration
Spring Boot provides auto-configuration for Spring WebFlux that works well with most applications.
The auto-configuration adds the following features on top of Spring's defaults:
* Configuring codecs for `HttpMessageReader` and `HttpMessageWriter` instances (described <<web#web.reactive.webflux.httpcodecs,later in this document>>).
* Support for serving static resources, including support for WebJars (described <<web#web.servlet.spring-mvc.static-content,later in this document>>).
If you want to keep Spring Boot WebFlux features and you want to add additional {spring-framework-docs}/web-reactive.html#webflux-config[WebFlux configuration], you can add your own `@Configuration` class of type `WebFluxConfigurer` but *without* `@EnableWebFlux`.
If you want to take complete control of Spring WebFlux, you can add your own `@Configuration` annotated with `@EnableWebFlux`.
[[web.reactive.webflux.httpcodecs]]
==== HTTP Codecs with HttpMessageReaders and HttpMessageWriters
Spring WebFlux uses the `HttpMessageReader` and `HttpMessageWriter` interfaces to convert HTTP requests and responses.
They are configured with `CodecConfigurer` to have sensible defaults by looking at the libraries available in your classpath.
Spring Boot provides dedicated configuration properties for codecs, `+spring.codec.*+`.
It also applies further customization by using `CodecCustomizer` instances.
For example, `+spring.jackson.*+` configuration keys are applied to the Jackson codec.
If you need to add or customize codecs, you can create a custom `CodecCustomizer` component, as shown in the following example:
[source,java,indent=0,subs="verbatim"]
----
include::{docs-java}/web/reactive/webflux/httpcodecs/MyCodecsConfiguration.java[]
----
You can also leverage <<web#web.servlet.spring-mvc.json,Boot's custom JSON serializers and deserializers>>.
[[web.reactive.webflux.static-content]]
==== Static Content
By default, Spring Boot serves static content from a directory called `/static` (or `/public` or `/resources` or `/META-INF/resources`) in the classpath.
It uses the `ResourceWebHandler` from Spring WebFlux so that you can modify that behavior by adding your own `WebFluxConfigurer` and overriding the `addResourceHandlers` method.
By default, resources are mapped on `+/**+`, but you can tune that by setting the configprop:spring.webflux.static-path-pattern[] property.
For instance, relocating all resources to `/resources/**` can be achieved as follows:
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
----
spring:
webflux:
static-path-pattern: "/resources/**"
----
You can also customize the static resource locations by using `spring.web.resources.static-locations`.
Doing so replaces the default values with a list of directory locations.
If you do so, the default welcome page detection switches to your custom locations.
So, if there is an `index.html` in any of your locations on startup, it is the home page of the application.
In addition to the "`standard`" static resource locations listed earlier, a special case is made for https://www.webjars.org/[Webjars content].
Any resources with a path in `+/webjars/**+` are served from jar files if they are packaged in the Webjars format.
TIP: Spring WebFlux applications do not strictly depend on the servlet API, so they cannot be deployed as war files and do not use the `src/main/webapp` directory.
[[web.reactive.webflux.welcome-page]]
==== Welcome Page
Spring Boot supports both static and templated welcome pages.
It first looks for an `index.html` file in the configured static content locations.
If one is not found, it then looks for an `index` template.
If either is found, it is automatically used as the welcome page of the application.
[[web.reactive.webflux.template-engines]]
==== Template Engines
As well as REST web services, you can also use Spring WebFlux to serve dynamic HTML content.
Spring WebFlux supports a variety of templating technologies, including Thymeleaf, FreeMarker, and Mustache.
Spring Boot includes auto-configuration support for the following templating engines:
* https://freemarker.apache.org/docs/[FreeMarker]
* https://mustache.github.io/[Mustache]
When you use one of these templating engines with the default configuration, your templates are picked up automatically from `src/main/resources/templates`.
[[web.reactive.webflux.error-handling]]
==== Error Handling
Spring Boot provides a `WebExceptionHandler` that handles all errors in a sensible way.
Its position in the processing order is immediately before the handlers provided by WebFlux, which are considered last.
For machine clients, it produces a JSON response with details of the error, the HTTP status, and the exception message.
For browser clients, there is a "`whitelabel`" error handler that renders the same data in HTML format.
You can also provide your own HTML templates to display errors (see the <<web#web.reactive.webflux.error-handling.error-pages,next section>>).
The first step to customizing this feature often involves using the existing mechanism but replacing or augmenting the error contents.
For that, you can add a bean of type `ErrorAttributes`.
To change the error handling behavior, you can implement `ErrorWebExceptionHandler` and register a bean definition of that type.
Because a `ErrorWebExceptionHandler` is quite low-level, Spring Boot also provides a convenient `AbstractErrorWebExceptionHandler` to let you handle errors in a WebFlux functional way, as shown in the following example:
[source,java,indent=0,subs="verbatim"]
----
include::{docs-java}/web/reactive/webflux/errorhandling/MyErrorWebExceptionHandler.java[]
----
For a more complete picture, you can also subclass `DefaultErrorWebExceptionHandler` directly and override specific methods.
In some cases, errors handled at the controller or handler function level are not recorded by the <<actuator#actuator.metrics.supported.spring-webflux, metrics infrastructure>>.
Applications can ensure that such exceptions are recorded with the request metrics by setting the handled exception as a request attribute:
[source,java,indent=0,subs="verbatim"]
----
include::{docs-java}/web/reactive/webflux/errorhandling/MyExceptionHandlingController.java[]
----
[[web.reactive.webflux.error-handling.error-pages]]
===== Custom Error Pages
If you want to display a custom HTML error page for a given status code, you can add a file to an `/error` directory.
Error pages can either be static HTML (that is, added under any of the static resource directories) or built with templates.
The name of the file should be the exact status code or a series mask.
For example, to map `404` to a static HTML file, your directory structure would be as follows:
[source,indent=0,subs="verbatim"]
----
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
----
To map all `5xx` errors by using a Mustache template, your directory structure would be as follows:
[source,indent=0,subs="verbatim"]
----
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.mustache
+- <other templates>
----
[[web.reactive.webflux.web-filters]]
==== Web Filters
Spring WebFlux provides a `WebFilter` interface that can be implemented to filter HTTP request-response exchanges.
`WebFilter` beans found in the application context will be automatically used to filter each exchange.
Where the order of the filters is important they can implement `Ordered` or be annotated with `@Order`.
Spring Boot auto-configuration may configure web filters for you.
When it does so, the orders shown in the following table will be used:
|===
| Web Filter | Order
| `MetricsWebFilter`
| `Ordered.HIGHEST_PRECEDENCE + 1`
| `WebFilterChainProxy` (Spring Security)
| `-100`
| `HttpTraceWebFilter`
| `Ordered.LOWEST_PRECEDENCE - 10`
|===
[[web.reactive.reactive-server]]
=== Embedded Reactive Server Support
Spring Boot includes support for the following embedded reactive web servers: Reactor Netty, Tomcat, Jetty, and Undertow.
Most developers use the appropriate “Starter” to obtain a fully configured instance.
By default, the embedded server listens for HTTP requests on port 8080.
[[web.reactive.reactive-server-resources-configuration]]
=== Reactive Server Resources Configuration
When auto-configuring a Reactor Netty or Jetty server, Spring Boot will create specific beans that will provide HTTP resources to the server instance: `ReactorResourceFactory` or `JettyResourceFactory`.
By default, those resources will be also shared with the Reactor Netty and Jetty clients for optimal performances, given:
* the same technology is used for server and client
* the client instance is built using the `WebClient.Builder` bean auto-configured by Spring Boot
Developers can override the resource configuration for Jetty and Reactor Netty by providing a custom `ReactorResourceFactory` or `JettyResourceFactory` bean - this will be applied to both clients and servers.
You can learn more about the resource configuration on the client side in the <<io#io.rest-client.webclient.runtime, WebClient Runtime section>>.