Proper WebFlux reference and MVC reference updates
Pending -- WebSocket, WebTestClient, more details around annotation processing, exception handling, and view resolution. Issue: SPR-15149, SPR-16009
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 70 KiB |
@@ -12,8 +12,8 @@ IoC container, with any web framework on top, but you can also use only the
|
||||
<<data-access.adoc#jdbc-introduction,JDBC abstraction layer>>. The Spring Framework supports declarative
|
||||
transaction management, remote access to your logic through RMI or web services, and various
|
||||
options for persisting your data.
|
||||
It offers full-featured web frameworks such as <<web.adoc#mvc-introduction,Spring MVC>>
|
||||
and <<reactive-web.adoc#webflux, Spring WebFlux>>; and it enables you to
|
||||
It offers full-featured web frameworks such as <<web.adoc#mvc,Spring Web MVC>>
|
||||
and <<web-reactive.adoc#webflux, Spring WebFlux>>; and it enables you to
|
||||
integrate <<core.adoc#aop-introduction,AOP>> transparently into your software.
|
||||
|
||||
This document is a reference guide to Spring Framework features. Questions on the
|
||||
@@ -29,7 +29,7 @@ This reference document provides the following sections:
|
||||
|
||||
* <<data-access.adoc#spring-data-tier,Data access and transaction management>>
|
||||
|
||||
* The Web on <<web.adoc#spring-web,Servlet>> or <<reactive-web.adoc#spring-webflux,Reactive>> stacks
|
||||
* The Web on <<web.adoc#spring-web,Servlet>> or <<web-reactive.adoc#spring-webflux,Reactive>> stacks
|
||||
|
||||
* <<kotlin.adoc#kotlin,Kotlin support>>
|
||||
|
||||
|
||||
@@ -1369,68 +1369,8 @@ and writes the media type supported by the Java I/O API.
|
||||
[[rest-async-resttemplate]]
|
||||
==== Async RestTemplate
|
||||
|
||||
Web applications often need to query external REST services those days. The very nature of
|
||||
HTTP and synchronous calls can lead up to challenges when scaling applications for those
|
||||
needs: multiple threads may be blocked, waiting for remote HTTP responses.
|
||||
|
||||
`AsyncRestTemplate` and <<rest-resttemplate>>'s APIs are very similar; see
|
||||
<<rest-overview-of-resttemplate-methods-tbl>>. The main difference between those APIs is
|
||||
that `AsyncRestTemplate` returns
|
||||
{api-spring-framework}/util/concurrent/ListenableFuture.html[`ListenableFuture`]
|
||||
wrappers as opposed to concrete results.
|
||||
|
||||
The previous `RestTemplate` example translates to:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
// async call
|
||||
Future<ResponseEntity<String>> futureEntity = template.getForEntity(
|
||||
"http://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42", "21");
|
||||
|
||||
// get the concrete result - synchronous call
|
||||
ResponseEntity<String> entity = futureEntity.get();
|
||||
----
|
||||
|
||||
{api-spring-framework}/util/concurrent/ListenableFuture.html[`ListenableFuture`]
|
||||
accepts completion callbacks:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
ListenableFuture<ResponseEntity<String>> futureEntity = template.getForEntity(
|
||||
"http://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42", "21");
|
||||
|
||||
// register a callback
|
||||
futureEntity.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
|
||||
@Override
|
||||
public void onSuccess(ResponseEntity<String> entity) {
|
||||
//...
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
//...
|
||||
}
|
||||
});
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
The default `AsyncRestTemplate` constructor registers a
|
||||
{api-spring-framework}/core/task/SimpleAsyncTaskExecutor.html[`SimpleAsyncTaskExecutor`
|
||||
] for executing HTTP requests.
|
||||
When dealing with a large number of short-lived requests, a thread-pooling TaskExecutor
|
||||
implementation like
|
||||
{api-spring-framework}/scheduling/concurrent/ThreadPoolTaskExecutor.html[`ThreadPoolTaskExecutor`]
|
||||
may be a good choice.
|
||||
====
|
||||
|
||||
See the
|
||||
{api-spring-framework}/util/concurrent/ListenableFuture.html[`ListenableFuture` javadocs]
|
||||
and
|
||||
{api-spring-framework}/web/client/AsyncRestTemplate.html[`AsyncRestTemplate` javadocs]
|
||||
for more details.
|
||||
The `AsyncRestTemplate` is deprecated.
|
||||
Please use the <<web-reactive.adoc#webflux-client,WebClient>> instead.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -261,7 +261,7 @@ for more details and up-to-date information.
|
||||
|
||||
Spring Framework now comes with a
|
||||
{doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/-router-function-dsl/[Kotlin routing DSL]
|
||||
that allows one to leverage the <<reactive-web#webflux-fn,WebFlux functional
|
||||
that allows one to leverage the <<web-reactive#webflux-fn,WebFlux functional
|
||||
API>> for writing clean and idiomatic Kotlin code:
|
||||
|
||||
[source,kotlin]
|
||||
@@ -583,7 +583,7 @@ https://spring.io/blog/2017/08/01/spring-framework-5-kotlin-apis-the-functional-
|
||||
=== Choosing the web flavor
|
||||
|
||||
Spring Framework now comes with 2 different web stacks: <<web#mvc,Spring MVC>> and
|
||||
<<reactive-web#spring-web-reactive,Spring WebFlux>>.
|
||||
<<web-reactive#spring-web-reactive,Spring WebFlux>>.
|
||||
|
||||
Spring WebFlux is recommended if one wants to create applications that will deal with latency,
|
||||
long-lived connections, streaming scenarios or simply if one wants to use the web functional
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
[[spring-reactive-web]]
|
||||
= Web on Reactive Stack
|
||||
:doc-root: https://docs.spring.io
|
||||
:api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework
|
||||
:toc: left
|
||||
:toclevels: 3
|
||||
:docinfo1:
|
||||
|
||||
This part of the documentation covers support for reactive stack, web applications built on
|
||||
http://www.reactive-streams.org/[Reactive Streams] and adapted to non-blocking runtimes
|
||||
such as Netty, Undertow, and Servlet containers via Servlet 3.1 non-blocking I/O.
|
||||
Individual chapters cover <<webflux-module, Spring WebFlux>> and its
|
||||
<<webflux-fn,functional programming model>>. The previous section covers support for
|
||||
<<web.adoc#spring-web,Servlet web>> applications.
|
||||
|
||||
[[spring-reactive-web-intro]]
|
||||
== Introduction
|
||||
|
||||
|
||||
[[spring-reactive-web-intro-reactive-programming]]
|
||||
=== What is Reactive Programming?
|
||||
|
||||
In plain terms reactive programming is about non-blocking applications that are asynchronous
|
||||
and event-driven and require a small number of threads to scale vertically (i.e. within the
|
||||
JVM) rather than horizontally (i.e. through clustering).
|
||||
|
||||
A key aspect of reactive applications is the concept of backpressure which is
|
||||
a mechanism to ensure producers don't overwhelm consumers. For example in a pipeline
|
||||
of reactive components extending from the database to the HTTP response when the
|
||||
HTTP connection is too slow the data repository can also slow down or stop completely
|
||||
until network capacity frees up.
|
||||
|
||||
Reactive programming also leads to a major shift from imperative to declarative async
|
||||
composition of logic. It is comparable to writing blocking code vs using the
|
||||
`CompletableFuture` from Java 8 to compose follow-up actions via lambda expressions.
|
||||
|
||||
For a longer introduction check the blog series
|
||||
https://spring.io/blog/2016/06/07/notes-on-reactive-programming-part-i-the-reactive-landscape["Notes on Reactive Programming"]
|
||||
by Dave Syer.
|
||||
|
||||
|
||||
[[spring-reactive-web-intro-reactive-api]]
|
||||
=== Reactive API and Building Blocks
|
||||
|
||||
Spring Framework 5 embraces
|
||||
https://github.com/reactive-streams/reactive-streams-jvm#reactive-streams[Reactive Streams]
|
||||
as the contract for communicating backpressure across async components and
|
||||
libraries. Reactive Streams is a specification created through industry collaboration that
|
||||
has also been adopted in Java 9 as `java.util.concurrent.Flow`.
|
||||
|
||||
The Spring Framework uses https://projectreactor.io/[Reactor] internally for its own
|
||||
reactive support. Reactor is a Reactive Streams implementation that further extends the
|
||||
basic Reactive Streams `Publisher` contract with the `Flux` and `Mono` composable API
|
||||
types to provide declarative operations on data sequences of `0..N` and `0..1`.
|
||||
|
||||
The Spring Framework exposes `Flux` and `Mono` in many of its own reactive APIs.
|
||||
At the application level however, as always, Spring provides choice and fully supports
|
||||
the use of RxJava. For more on reactive types check the post
|
||||
https://spring.io/blog/2016/04/19/understanding-reactive-types["Understanding Reactive Types"]
|
||||
by Sebastien Deleuze.
|
||||
|
||||
include::web/webflux.adoc[leveloffset=+1]
|
||||
15
src/docs/asciidoc/web-reactive.adoc
Normal file
15
src/docs/asciidoc/web-reactive.adoc
Normal file
@@ -0,0 +1,15 @@
|
||||
[[spring-web-reactive]]
|
||||
= Web on Reactive Stack
|
||||
:doc-root: https://docs.spring.io
|
||||
:api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework
|
||||
:toc: left
|
||||
:toclevels: 4
|
||||
:docinfo1:
|
||||
|
||||
This part of the documentation covers support for reactive stack, web applications built on a
|
||||
http://www.reactive-streams.org/[Reactive Streams] API to run on top of non-blocking
|
||||
servers such as Netty, Undertow, and Servlet 3.1+ containers. Individual chapters cover
|
||||
<<webflux-module, Spring WebFlux>> and its <<webflux-fn,functional programming model>>.
|
||||
For Servlet stack, web applications, to go <<web.adoc#spring-web,Web on Servlet Stack>>.
|
||||
|
||||
include::web/webflux.adoc[leveloffset=+1]
|
||||
@@ -9,7 +9,7 @@
|
||||
This part of the documentation covers support for Servlet stack, web applications built on the
|
||||
Servlet API and deployed to Servlet containers. Individual chapters include <<mvc,Spring MVC>>,
|
||||
<<mvc-view,View Technologies>>, <<mvc-cors,CORS Support>>, and <<websocket,WebSocket Support>>.
|
||||
The next section covers support for <<reactive-web.adoc#spring-reactive-web,reactive web>> applications.
|
||||
For reactive stack, web applications, go to <<web-reactive.adoc#spring-web-reactive,Web on Reactive Stack>>.
|
||||
|
||||
include::web/webmvc.adoc[leveloffset=+1]
|
||||
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
[[webflux-fn]]
|
||||
= Functional Programming Model
|
||||
= Functional Endpoints
|
||||
|
||||
Spring WebFlux provides a lightweight, functional programming model where functions
|
||||
are used to route and handle requests and where contracts are designed for immutability.
|
||||
It is an alternative to the annotated-based programming model but runs on the same
|
||||
<<web-reactive.adoc#webflux-reactive-spring-web>> foundation
|
||||
|
||||
|
||||
[[webflux-fn-handler-functions]]
|
||||
== HandlerFunctions
|
||||
== HandlerFunction
|
||||
|
||||
Incoming HTTP requests are handled by a **`HandlerFunction`**, which is essentially a function that
|
||||
takes a `ServerRequest` and returns a `Mono<ServerResponse>`. The annotation counterpart to a
|
||||
handler function would be a method with `@RequestMapping`.
|
||||
handler function is an `@RequestMapping` method.
|
||||
|
||||
`ServerRequest` and `ServerResponse` are immutable interfaces that offer JDK-8 friendly access
|
||||
to the underlying HTTP messages. Both are fully reactive by
|
||||
building on top of Reactor: the request expose the body as `Flux` or `Mono`; the response accepts
|
||||
any http://www.reactive-streams.org[Reactive Streams] `Publisher` as body.
|
||||
to the underlying HTTP messages with http://www.reactive-streams.org[Reactive Streams]
|
||||
non-blocking back pressure. The request exposes the body as Reactor `Flux` or `Mono`
|
||||
types; the response accepts any Reactive Streams `Publisher` as body (see
|
||||
<<web-reactive.adoc#webflux-reactive-libraries,Reactive Libraries>>).
|
||||
|
||||
|
||||
`ServerRequest` gives access to various HTTP request elements:
|
||||
the method, URI, query parameters, and -- through the separate `ServerRequest.Headers` interface
|
||||
@@ -26,7 +34,7 @@ contains JSON, or JAXB if XML).
|
||||
|
||||
Flux<Person> people = request.bodyToFlux(Person.class);
|
||||
|
||||
The two methods above (`bodyToMono` and `bodyToFlux`) are, in fact, convenience methods that use the
|
||||
The above -- `bodyToMono` and `bodyToFlux`, are, in fact, convenience methods that use the
|
||||
generic `ServerRequest.body(BodyExtractor)` method. `BodyExtractor` is
|
||||
a functional strategy interface that allows you to write your own extraction logic, but common
|
||||
`BodyExtractor` instances can be found in the `BodyExtractors` utility class. So, the above
|
||||
@@ -43,7 +51,8 @@ a JSON content-type, and a body:
|
||||
Mono<Person> person = ...
|
||||
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person);
|
||||
|
||||
And here is how to build a response with a 201 Created status, Location header, and empty body:
|
||||
And here is how to build a response with a 201 CREATED status, a `"Location"` header, and
|
||||
empty body:
|
||||
|
||||
URI location = ...
|
||||
ServerResponse.created(location).build();
|
||||
@@ -111,7 +120,7 @@ variable `id`. We retrieve that `Person` via the repository, and create a JSON r
|
||||
found. If it is not found, we use `switchIfEmpty(Mono<T>)` to return a 404 Not Found response.
|
||||
|
||||
[[webflux-fn-router-functions]]
|
||||
== RouterFunctions
|
||||
== RouterFunction
|
||||
|
||||
Incoming requests are routed to handler functions with a **`RouterFunction`**, which is a function
|
||||
that takes a `ServerRequest`, and returns a `Mono<HandlerFunction>`. If a request matches a
|
||||
@@ -172,43 +181,23 @@ Most of the predicates found in `RequestPredicates` are compositions.
|
||||
For instance, `RequestPredicates.GET(String)` is a composition of
|
||||
`RequestPredicates.method(HttpMethod)` and `RequestPredicates.path(String)`.
|
||||
|
||||
|
||||
[[webflux-fn-running]]
|
||||
=== Running a Server
|
||||
== Running a server
|
||||
|
||||
Now there is just one piece of the puzzle missing: running a router function in an HTTP server.
|
||||
You can convert a router function into a `HttpHandler` by using
|
||||
`RouterFunctions.toHttpHandler(RouterFunction)`.
|
||||
The `HttpHandler` allows you to run on a wide variety of reactive runtimes: Reactor Netty,
|
||||
Servlet 3.1+, and Undertow.
|
||||
Here is how we run a router function in Reactor Netty, for instance:
|
||||
How do you run a router function in an HTTP server? A simple option is to convert a
|
||||
router function to an `HttpHandler` via `RouterFunctions.toHttpHandler(RouterFunction)`.
|
||||
The `HttpHandler` can then be used with a number of servers adapters.
|
||||
See <<web-reactive.adoc#webflux-httphandler,HttpHandler>> for server-specific
|
||||
instructions.
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
RouterFunction<ServerResponse> route = ...
|
||||
HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
|
||||
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
|
||||
HttpServer server = HttpServer.create(HOST, PORT);
|
||||
server.newHandler(adapter).block();
|
||||
----
|
||||
|
||||
For Tomcat it looks like this:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
RouterFunction<ServerResponse> route = ...
|
||||
HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
|
||||
HttpServlet servlet = new ServletHttpHandlerAdapter(httpHandler);
|
||||
Tomcat server = new Tomcat();
|
||||
Context rootContext = server.addContext("", System.getProperty("java.io.tmpdir"));
|
||||
Tomcat.addServlet(rootContext, "servlet", servlet);
|
||||
rootContext.addServletMapping("/", "servlet");
|
||||
tomcatServer.start();
|
||||
----
|
||||
it is also possible to run with a
|
||||
<<web-reactive.adoc#webflux-dispatcher-handler,DispatcherHandler>> setup -- side by side
|
||||
with annotated controllers. The easiest way to do that is through the
|
||||
<<web-reactive.adoc#webflux-config>> which creates the necessary configuration to
|
||||
handle requests with router and handler functions.
|
||||
|
||||
|
||||
// TODO: DispatcherHandler
|
||||
|
||||
[[webflux-fn-handler-filter-function]]
|
||||
== HandlerFilterFunction
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user