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:
Rossen Stoyanchev
2017-09-13 21:02:28 -04:00
parent 41b53de644
commit 9d5a25e737
10 changed files with 2341 additions and 1466 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -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>>

View File

@@ -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.

View File

@@ -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

View File

@@ -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]

View 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]

View File

@@ -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]

View File

@@ -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