Skip to content

Commit 963ea06

Browse files
committed
Update Spring Web Reactive reference documentation
Issue: SPR-14912
1 parent 209e7a7 commit 963ea06

File tree

2 files changed

+158
-52
lines changed

2 files changed

+158
-52
lines changed
69.7 KB
Loading

src/asciidoc/web-reactive.adoc

Lines changed: 158 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,20 @@ by Sebastien Deleuze.
5050
[[web-reactive-feature-overview]]
5151
== Spring Web Reactive Overview
5252

53+
Spring Framework 5 adds a new `spring-web-reactive` module that provides both reactive
54+
client and server.
5355

54-
[[web-reactive-module]]
55-
=== Spring Web Reactive Module
56+
[[web-reactive-server]]
57+
=== Reactive Web Server
5658

59+
The reactive web server is available in 2 flavors:
5760

58-
Spring Framework 5 adds a new `spring-web-reactive` module that supports the same
59-
`@Controller` programming model as Spring MVC but executed on a reactive,
60-
non-blocking engine. The diagram below shows how Spring MVC and Spring Web
61-
Reactive compare side by side:
61+
* With the same `@Controller` annotation-based programming model than Spring MVC
62+
* With a new functional programming model using Java 8 lambdas
63+
64+
When using Spring Web Reactive, regardless of the programming model you choose, your
65+
application is executed on a reactive non-blocking engine. The diagram below shows how
66+
Spring MVC and Spring Web Reactive compare side by side:
6267

6368
image::images/web-reactive-overview.png[width=720]
6469

@@ -69,51 +74,90 @@ Each runtime is adapted to a set of shared, reactive `ServerHttpRequest` and
6974
as `Flux<DataBuffer>` with full backpressure support on the read and the
7075
write side.
7176

72-
The `spring-core` module provides reactive `Encoder` and `Decoder` contracts
73-
that enable the serialization of a `Flux` of bytes to and from typed objects.
74-
The `spring-web` module adds JSON (Jackson) and XML (JAXB) implementations for use in
75-
web applications as well as others for SSE streaming and zero-copy file transfer.
77+
JSON or XML REST webservices are supported, as well as view rendering, server-sent events
78+
and Websocket.
7679

77-
The `spring-web-reactive` module contains the Spring Web Reactive framework that supports
78-
the `@Controller` programming model. It re-defines many of the Spring MVC contracts
79-
such as `HandlerMapping` and `HandlerAdapter` to be asynchronous and
80-
non-blocking and to operate on the reactive HTTP request and response. For this reason
80+
[[web-reactive-server-annotation]]
81+
==== Annotation-based programming model
82+
83+
The `@Controller` programming model supported by Spring Web Reactive re-defines many of
84+
the Spring MVC contracts such as `HandlerMapping` and `HandlerAdapter` to be asynchronous
85+
and non-blocking and to operate on the reactive HTTP request and response. For this reason
8186
Spring MVC and Spring Web Reactive cannot share any code. However they do share
8287
many of the same algorithms.
8388

8489
The end result is a programming model identical to today's Spring MVC but
8590
with support for reactive types and executed in a reactive manner.
86-
For example a controller method can declare a `@RequestBody` method argument
87-
in any one of the following ways:
8891

89-
* `Account account` -- the account is deserialized without
90-
blocking before the controller is invoked.
91-
* `Mono<Account> account` -- the controller can use the `Mono`
92-
to declare logic to be executed after the account is deserialized.
93-
* `Single<Account> account` -- same as with `Mono` but using RxJava
94-
* `Flux<Account> accounts` -- input streaming scenario.
95-
* `Observable<Account> accounts` -- input streaming with RxJava.
92+
Here is an example of a reactive controller declared with annotations:
9693

97-
Similarly a controller can also an `@ResponseBody` return value
98-
in any one of the following ways:
94+
[source,java,indent=0]
95+
[subs="verbatim,quotes"]
96+
----
97+
@RestController
98+
public class PersonController {
99+
100+
private final PersonRepository repository;
101+
102+
public PersonController(PersonRepository repository) {
103+
this.repository = repository;
104+
}
105+
106+
@PostMapping("/person")
107+
Mono<Void> create(@RequestBody Publisher<Person> personStream) {
108+
return this.repository.save(personStream).then();
109+
}
110+
111+
@GetMapping("/person")
112+
Flux<Person> list() {
113+
return this.repository.findAll();
114+
}
115+
116+
@GetMapping("/person/{id}")
117+
Mono<Person> findById(@PathVariable String id) {
118+
return this.repository.findOne(id);
119+
}
120+
}
121+
----
99122

100-
* `Mono<Account>` -- serialize without blocking the given Account when the `Mono` completes.
101-
* `Single<Account>` -- same but using RxJava.
102-
* `Flux<Account>` -- streaming scenario, possibly SSE depending on the requested content type.
103-
* `Observable<Account>` -- same but using RxJava `Observable` type.
104-
* `Flowable<Account>` -- same but using RxJava 2 `Flowable` type.
105-
* `Flux<ServerSentEvent>` -- SSE streaming.
106-
* `Mono<Void>` -- request handling completes when the `Mono` completes.
107-
* `void` -- request handling completes when the method returns;
108-
implies a synchronous, non-blocking controller method.
109-
* `Account` -- serialize without blocking the given Account;
110-
implies a synchronous, non-blocking controller method.
123+
[[web-reactive-server-functional]]
124+
==== Functional programming model
111125

126+
The functional programming model uses Java 8 lambdas instead of annotations to allow you
127+
to create a web application. It is built on top of simple but powerful building blocks like
128+
`RouterFunction` and `HandlerFunction`. For more details, see this
129+
https://spring.io/blog/2016/09/22/new-in-spring-5-functional-web-framework[blog post].
130+
131+
Here is an example of a Spring web functional controller:
132+
133+
[source,java,indent=0]
134+
[subs="verbatim,quotes"]
135+
----
136+
PersonRepository repository = ...
137+
138+
RouterFunctions
139+
.route(GET("/person/{id}").and(accept(APPLICATION_JSON)), request -> {
140+
int personId = Integer.valueOf(request.pathVariable("id"));
141+
Mono<ServerResponse> notFound = ServerResponse.notFound().build();
142+
return repository.findOne(personId)
143+
.then(person -> ServerResponse.ok().body(Mono.just(person), Person.class))
144+
.otherwiseIfEmpty(notFound);
145+
})
146+
147+
.andRoute(GET("/person").and(accept(APPLICATION_JSON)), request ->
148+
ServerResponse.ok().body(repository.findAll(), Person.class))
149+
150+
.andRoute(POST("/person").and(contentType(APPLICATION_JSON)), request ->
151+
ServerResponse.ok().build(repository.save(request.bodyToMono(Person.class))));
152+
----
112153

113154
[[web-reactive-client]]
114155
=== Reactive Web Client
115156

116-
Spring Framework 5 adds a new reactive `WebClient` in addition to the existing `RestTemplate`.
157+
Spring Framework 5 adds a new reactive `WebClient` in addition to the existing `RestTemplate`
158+
and `AsyncRestTemplate`. In addition to a revised API, a big difference between
159+
`AsyncRestTemplate` and the reactive `WebClient` is that the later allows to consume
160+
streaming APIs like https://dev.twitter.com/streaming/overview[Twitter one] for example.
117161

118162
A `WebClient` instance use a `ClientHttpConnector` implementation to drive the underlying
119163
supported HTTP client (e.g. Reactor Netty). This client is adapted to a set of shared,
@@ -135,9 +179,44 @@ ClientRequest<Void> request = ClientRequest.GET("http://example.com/accounts/{id
135179
136180
Mono<Account> account = this.webClient
137181
.exchange(request)
138-
.then(response -> response.body(toMono(Account.class)));
182+
.then(response -> response.bodyToMono(Account.class));
139183
----
140184

185+
A `WebSocketClient` is also available.
186+
187+
[[web-reactive-http-body]]
188+
=== Reading and writing HTTP body
189+
190+
The `spring-core` module provides reactive `Encoder` and `Decoder` contracts
191+
that enable the serialization of a `Flux` of bytes to and from typed objects.
192+
The `spring-web` module adds JSON (Jackson) and XML (JAXB) implementations for use in
193+
web applications as well as others for SSE streaming and zero-copy file transfer.
194+
195+
Whether you use the annotation-based or functional programming model, the request body
196+
provided can be for example one of the following ways:
197+
198+
* `Account account` -- the account is deserialized without
199+
blocking before the controller is invoked.
200+
* `Mono<Account> account` -- the controller can use the `Mono`
201+
to declare logic to be executed after the account is deserialized.
202+
* `Single<Account> account` -- same as with `Mono` but using RxJava
203+
* `Flux<Account> accounts` -- input streaming scenario.
204+
* `Observable<Account> accounts` -- input streaming with RxJava.
205+
206+
Similarly, the response body can be in any one of the following ways:
207+
208+
* `Mono<Account>` -- serialize without blocking the given Account when the `Mono` completes.
209+
* `Single<Account>` -- same but using RxJava.
210+
* `Flux<Account>` -- streaming scenario, possibly SSE depending on the requested content type.
211+
* `Observable<Account>` -- same but using RxJava `Observable` type.
212+
* `Flowable<Account>` -- same but using RxJava 2 `Flowable` type.
213+
* `Flux<ServerSentEvent>` -- SSE streaming.
214+
* `Mono<Void>` -- request handling completes when the `Mono` completes.
215+
* `Account` -- serialize without blocking the given Account;
216+
implies a synchronous, non-blocking controller method.
217+
* `void` -- specific to the annotation-based programming model, request handling completes
218+
when the method returns; implies a synchronous, non-blocking controller method.
219+
141220
[[web-reactive-getting-started]]
142221
== Getting Started
143222

@@ -147,19 +226,21 @@ Mono<Account> account = this.webClient
147226

148227
The
149228
https://github.com/bclozel/spring-boot-web-reactive#spring-boot-web-reactive-starter[Spring Boot Web Reactive starter]
150-
available via http://start.spring.io
151-
is the fastest way to get started. It does all that's necessary so you can start
229+
available via http://start.spring.io is the fastest way to get started if you want to use
230+
the annotation-based programming model. It does all that's necessary so you can start
152231
writing `@Controller` classes. By default it runs on Tomcat but the dependencies can
153232
be changed as usual with Spring Boot to switch to a different runtime.
154233

234+
There is no Spring Boot Starter available yet for the functional programming model, so for
235+
this one use the manual bootstraping method described bellow.
155236

156237
[[web-reactive-getting-started-manual]]
157238
=== Manual Bootstrapping
158239

159240
This section outlines the steps to get up and running without Spring Boot.
160241

161242
For dependencies start with `spring-web-reactive` and `spring-context`.
162-
Then add `jackson-databind` and `io.netty:netty-buffer:4.1.3.Final`
243+
Then add `jackson-databind` and `io.netty:netty-buffer`
163244
(temporarily see https://jira.spring.io/browse/SPR-14528[SPR-14528]) for JSON support.
164245
Lastly add the dependencies for one of the supported runtimes:
165246

@@ -169,7 +250,7 @@ Lastly add the dependencies for one of the supported runtimes:
169250
* RxNetty -- `io.reactivex:rxnetty-common` and `io.reactivex:rxnetty-http`
170251
* Undertow -- `io.undertow:undertow-core`
171252

172-
For the bootstrap code start with:
253+
For the **annotation-based programming model**, bootstrap code start with:
173254
[source,java,indent=0]
174255
[subs="verbatim,quotes"]
175256
----
@@ -180,7 +261,25 @@ HttpHandler handler = DispatcherHandler.toHttpHandler(context); // (2)
180261
The above loads default Spring Web Reactive config (1), then creates a
181262
`DispatcherHandler`, the main class driving request processing (2), and adapts
182263
it to `HttpHandler`, the lowest level Spring abstraction for reactive HTTP request handling.
183-
An `HttpHandler` can then be installed in each supported runtime:
264+
265+
For the **functional programming model**, bootstrap code start with:
266+
[source,java,indent=0]
267+
[subs="verbatim,quotes"]
268+
----
269+
ApplicationContext context = new AnnotationConfigApplicationContext(); // (1)
270+
context.registerBean(FooBean.class, () -> new FooBeanImpl()); // (2)
271+
context.registerBean(BarBean.class); // (3)
272+
HttpHandler handler = WebHttpHandlerBuilder
273+
.webHandler(RouterFunctions.toHttpHandler(...))
274+
.applicationContext(context)
275+
.build(); // (4)
276+
----
277+
278+
The above creates an `AnnotationConfigApplicationContext` instance (1) that can take advantage
279+
of the new functional bean registration API (2) to register beans using a Java 8 `Supplier`
280+
or just by specifying its class (3). The `HttpHandler` is created using `WebHttpHandlerBuilder` (4).
281+
282+
**Common to both** annotation and functional flavors, an `HttpHandler` can then be installed in each supported runtime:
184283

185284
[source,java,indent=0]
186285
[subs="verbatim,quotes"]
@@ -191,8 +290,10 @@ HttpServlet servlet = new ServletHttpHandlerAdapter(handler);
191290
192291
// Reactor Netty
193292
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
194-
HttpServer server = HttpServer.create(host, port);
195-
server.startAndAwait(adapter);
293+
HttpServer.create(host, port)
294+
.newHandler(adapter)
295+
.doOnNext(c -> System.out.println("Server listening on " + c.address())).block()
296+
.onClose().block();
196297
197298
// RxNetty
198299
RxNettyHttpHandlerAdapter adapter = new RxNettyHttpHandlerAdapter(handler);
@@ -213,12 +314,17 @@ and it registers for you the `ServletHttpHandlerAdapter` shown above.
213314
Only implement one method to point to your Spring Java configuration classes.
214315
====
215316

317+
[[web-reactive-getting-started-examples]]
318+
=== Examples
216319

320+
You will find code examples useful to build your own Spring Web Reactive application in these projects:
217321

218-
219-
[[web-reactive-getting-started-M1]]
220-
=== Extent of Support in 5.0 M1
221-
222-
For M1 the Spring Web Reactive module focuses on REST scenarios for both
223-
client and server. Basic HTML rendering with Freemarker is also supported but
224-
limited to rendering but not form submissions.
322+
* https://github.com/bclozel/spring-boot-web-reactive[Spring Boot Web Reactive Starter]: sources of the reactive starter available at http://start.spring.io
323+
* https://github.com/poutsma/web-function-sample[Functional programming model sample]
324+
* https://github.com/sdeleuze/spring-reactive-playground[Spring Reactive Playground]: plaground for most Spring Web Reactive features
325+
* https://github.com/reactor/projectreactor.io/tree/spring-functional[Reactor website]: the `spring-functional` branch is a Spring Web Reactive functional web application
326+
* https://github.com/bclozel/spring-reactive-university[Spring Reactive University]: live-coded project from https://www.youtube.com/watch?v=Cj4foJzPF80[this Devoxx BE 2106 university talk]
327+
* https://github.com/thymeleaf/thymeleafsandbox-biglist-reactive[Reactive Thymeleaf Sandbox]
328+
* https://github.com/mix-it/mixit/[Mix-it 2017 website]: Kotlin + Reactive + Functional web and bean registration API application
329+
* https://github.com/simonbasle/reactor-by-example[Reactor by example]: code snippets coming from this https://www.infoq.com/articles/reactor-by-example[InfoQ article]
330+
* https://github.com/spring-projects/spring-framework/tree/master/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation[Spring Web Reactive integration tests]: various features tested with Reactor https://projectreactor.io/docs/test/release/api/index.html?reactor/test/StepVerifier.html[`StepVerifier`]

0 commit comments

Comments
 (0)