Skip to content

Commit 6bf1281

Browse files
committed
More documentation updates
1 parent e62b104 commit 6bf1281

File tree

1 file changed

+150
-100
lines changed

1 file changed

+150
-100
lines changed

src/asciidoc/web-reactive.adoc

Lines changed: 150 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,36 @@
11
[[web-reactive]]
22
= Web Reactive Framework
3-
This section provides basic information on the Spring Web Reactive support in Spring Framework 5.
3+
This section provides basic information on the reactive programming
4+
support for Web applications in Spring Framework 5.
45

56

67
[[web-reactive-intro]]
78
== Introduction
89

910

1011
[[web-reactive-programming]]
11-
=== Reactive Programming
12+
=== What is Reactive Programming?
1213

1314
In plain terms reactive programming is about non-blocking applications that are asynchronous
14-
and event-driven and require a small number of threads to scale. A key aspect of that
15-
definition is the concept of backpressure which is a mechanism to ensure producers
16-
don't overwhelm consumers. For example in a pipeline of reactive components that extends
17-
from the database to the HTTP socket when the HTTP client is slow the data
18-
repository slows down or stops until capacity frees up.
15+
and event-driven and require a small number of threads to scale vertically (i.e. within the
16+
JVM) rather than horizontally (i.e. through clustering).
1917

20-
From a programming model perspective reactive programming involves a major shift from imperative style logic
21-
to a declarative composition of async logic. It is comparable to using `CompletableFuture` in Java 8
22-
and composing follow-up actions via lambda expressions.
18+
A key aspect of the reactive applications is the concept of backpressure which is
19+
a mechanism to ensure producers don't overwhelm consumers. For example in a pipeline
20+
of reactive components extending from the database to the HTTP connection when the
21+
HTTP client is slow the data repository also slows down or stops until capacity frees up.
22+
23+
Reactive programming also involves a major shift from imperative style logic
24+
to declarative async composition of logic. It is comparable to using `CompletableFuture`
25+
in Java 8 and composing follow-up actions via lambda expressions.
2326

2427
For a more extended introduction to reactive programming check the excellent multi-part series
2528
https://spring.io/blog/2016/06/07/notes-on-reactive-programming-part-i-the-reactive-landscape["Notes on Reactive Programming"]
2629
by Dave Syer.
2730

2831

2932
[[web-reactive-api]]
30-
=== Spring Web Reactive Types
33+
=== Reactive API and Building Blocks
3134

3235
Spring Framework 5 embraces
3336
https://github.com/reactive-streams/reactive-streams-jvm#reactive-streams[Reactive Streams]
@@ -50,46 +53,44 @@ by Sebastien Deleuze.
5053
[[web-reactive-feature-overview]]
5154
== Spring Web Reactive Overview
5255

53-
Spring Framework 5 adds a new `spring-web-reactive` module that provides both reactive
54-
client and server.
56+
Spring Framework 5 includes a new `spring-web-reactive` module. The module contains support
57+
for reactive HTTP and WebSocket clients as well as for reactive server web applications
58+
including REST, HTML browser, and WebSocket style interactions.
5559

5660
[[web-reactive-server]]
57-
=== Reactive Web Server
61+
=== Server-Side Reactive Web Support
5862

59-
The reactive web server is available in 2 flavors:
63+
On the server-side the new reactive module supports 2 distinct programming models:
6064

61-
* With the same `@Controller` annotation-based programming model than Spring MVC
62-
* With a new functional programming model using Java 8 lambdas
65+
* Annotation-based with `@Controller` and the other annotations supported also with Spring MVC
66+
* Functional, Java 8 lambda style routing and handling
6367

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:
68+
Both programming models are executed on the same reactive foundation that adapts
69+
non-blocking HTTP runtimes to the Reactive Streams API. The diagram
70+
below shows the server-side stack including traditional, Servlet-based
71+
Spring MVC on the left from the `spring-web-mvc` module and also the
72+
reactive stack on the right from the `spring-web-reactive` module.
6773

6874
image::images/web-reactive-overview.png[width=720]
6975

70-
Spring Web Reactive makes use of Servlet 3.1 non-blocking I/O and runs on
71-
Servlet 3.1 containers. It also runs on non-Servlet runtimes such as Netty and Undertow.
72-
Each runtime is adapted to a set of shared, reactive `ServerHttpRequest` and
73-
`ServerHttpResponse` abstractions that expose the request and response body
74-
as `Flux<DataBuffer>` with full backpressure support on the read and the
75-
write side.
76-
77-
JSON or XML REST webservices are supported, as well as view rendering, server-sent events
78-
and Websocket.
76+
The new reactive stack can run on Servlet containers with support for the
77+
Servlet 3.1 Non-Blocking IO API as well as on other async runtimes such as
78+
Netty and Undertow. Each runtime is adapted to a reactive
79+
`ServerHttpRequest` and `ServerHttpResponse` exposing the body of the
80+
request and response as `Flux<DataBuffer>`, rather than
81+
`InputStream` and `OutputStream`, with reactive backpressure.
82+
REST-style JSON and XML serialization and deserialization is supported on top
83+
as a `Flux<Object>`, and so is HTML view rendering and Server-Sent Events.
7984

8085
[[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
86-
Spring MVC and Spring Web Reactive cannot share any code. However they do share
87-
many of the same algorithms.
86+
==== Annotation-based Programming Model
8887

89-
The end result is a programming model identical to today's Spring MVC but
90-
with support for reactive types and executed in a reactive manner.
91-
92-
Here is an example of a reactive controller declared with annotations:
88+
The same `@Controller` programming model and the same annotations used in Spring MVC
89+
are also supported on the reactive side. The main difference is that the framework
90+
contracts underneath -- i.e. `HandlerMapping`, `HandlerAdapter`, are
91+
non-blocking and operate on the reactive `ServerHttpRequest` and `ServerHttpResponse`
92+
rather than on the `HttpServletRequest` and `HttpServletResponse`.
93+
Below is an example with a reactive controller:
9394

9495
[source,java,indent=0]
9596
[subs="verbatim,quotes"]
@@ -121,14 +122,12 @@ public class PersonController {
121122
----
122123

123124
[[web-reactive-server-functional]]
124-
==== Functional programming model
125-
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].
125+
==== Functional Programming Model
130126

131-
Here is an example of a Spring web functional controller:
127+
The functional programming model uses Java 8 lambda style routing and request
128+
handling instead of annotations. The main API contracts are functional interfaces named
129+
`RouterFunction` and `HandlerFunction`. They are simple but powerful building blocks
130+
for creating web applications. Below is an example of functional request handling:
132131

133132
[source,java,indent=0]
134133
[subs="verbatim,quotes"]
@@ -143,67 +142,71 @@ RouterFunctions
143142
.then(person -> ServerResponse.ok().body(Mono.just(person), Person.class))
144143
.otherwiseIfEmpty(notFound);
145144
})
146-
147145
.andRoute(GET("/person").and(accept(APPLICATION_JSON)), request ->
148146
ServerResponse.ok().body(repository.findAll(), Person.class))
149-
150147
.andRoute(POST("/person").and(contentType(APPLICATION_JSON)), request ->
151148
ServerResponse.ok().build(repository.save(request.bodyToMono(Person.class))));
152149
----
153150

154-
[[web-reactive-client]]
155-
=== Reactive Web Client
151+
For more on the functional programming model see the
152+
https://spring.io/blog/2016/09/22/new-in-spring-5-functional-web-framework[M3 release blog post].
156153

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

162-
A `WebClient` instance use a `ClientHttpConnector` implementation to drive the underlying
163-
supported HTTP client (e.g. Reactor Netty). This client is adapted to a set of shared,
164-
reactive `ClientHttpRequest` and `ClientHttpResponse` abstractions that expose the request
165-
and response body as `Flux<DataBuffer>` with full backpressure support on the read and
166-
the write side. The `HttpMessageReader` and `HttpMessageWriter` abstractions are also used on
167-
the client side for the serialization of a `Flux` of bytes to and from typed objects.
155+
[[web-reactive-client]]
156+
=== Client-Side Reactive Web Support
168157

169-
An example of using the `WebClient`:
158+
Spring Framework 5 includes a functional, reactive `WebClient` that offers a fully
159+
non-blocking and reactive alternative to the `RestTemplate`. It exposes network
160+
input and output as a reactive `ClientHttpRequest` and `ClientHttpRespones` where
161+
the body of the request and response is a `Flux<DataBuffer>` rather than an
162+
`InputStream` and `OutputStream`. In addition it supports the same reactive JSON, XML,
163+
and SSE serialization mechanism as on the server side so you can work with typed objects.
164+
Below is an example of using the `WebClient` which requires a `ClientHttpConnector`
165+
implementation to plug in a specific HTTP client such as Reactor Netty:
170166

171167
[source,java,indent=0]
172168
[subs="verbatim,quotes"]
173169
----
174-
// create an immutable instance of WebClient
175-
WebClient webClient = WebClient.create(new ReactorClientHttpConnector());
170+
WebClient client = WebClient.create(new ReactorClientHttpConnector());
176171
177-
ClientRequest<Void> request = ClientRequest.GET("http://example.com/accounts/{id}", 1L)
178-
.accept(MediaType.APPLICATION_JSON).build();
172+
ClientRequest<Void> request = ClientRequest
173+
.GET("http://example.com/accounts/{id}", 1L)
174+
.accept(APPLICATION_JSON)
175+
.build();
179176
180-
Mono<Account> account = this.webClient
181-
.exchange(request)
182-
.then(response -> response.bodyToMono(Account.class));
177+
Mono<Account> account = client
178+
.exchange(request)
179+
.then(response -> response.bodyToMono(Account.class));
183180
----
184181

185-
A `WebSocketClient` is also available.
182+
183+
[NOTE]
184+
====
185+
The `AsyncRestTemplate` also supports non-blocking interactions. The main difference
186+
is it can't support non-blocking streaming, like for example
187+
https://dev.twitter.com/streaming/overview[Twitter one], because fundamentally it's
188+
still based and relies on `InputStream` and `OutputStream`.
189+
====
190+
186191

187192
[[web-reactive-http-body]]
188-
=== Reading and writing HTTP body
193+
=== Encoding and Decoding the Request and Response Body
189194

190195
The `spring-core` module provides reactive `Encoder` and `Decoder` contracts
191196
that enable the serialization of a `Flux` of bytes to and from typed objects.
192197
The `spring-web` module adds JSON (Jackson) and XML (JAXB) implementations for use in
193198
web applications as well as others for SSE streaming and zero-copy file transfer.
194199

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:
200+
For example the request body can be one of the following way and it will be decoded
201+
automatically in both the annotation and the functional programming models:
197202

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.
203+
* `Account account` -- the account is deserialized without blocking before the controller is invoked.
204+
* `Mono<Account> account` -- the controller can use the `Mono` to declare logic to be executed after the account is deserialized.
202205
* `Single<Account> account` -- same as with `Mono` but using RxJava
203206
* `Flux<Account> accounts` -- input streaming scenario.
204207
* `Observable<Account> accounts` -- input streaming with RxJava.
205208

206-
Similarly, the response body can be in any one of the following ways:
209+
The response body can be one of the following:
207210

208211
* `Mono<Account>` -- serialize without blocking the given Account when the `Mono` completes.
209212
* `Single<Account>` -- same but using RxJava.
@@ -212,11 +215,54 @@ Similarly, the response body can be in any one of the following ways:
212215
* `Flowable<Account>` -- same but using RxJava 2 `Flowable` type.
213216
* `Flux<ServerSentEvent>` -- SSE streaming.
214217
* `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.
218+
* `Account` -- serialize without blocking the given Account; implies a synchronous, non-blocking controller method.
217219
* `void` -- specific to the annotation-based programming model, request handling completes
218220
when the method returns; implies a synchronous, non-blocking controller method.
219221

222+
[[web-reactive-websocket-support]]
223+
=== Reactive WebSocket Support
224+
225+
The Spring Framework 5 `spring-web-reactive` module includes reactive WebSocket
226+
client and server support. Both client and server are supported on the Java WebSocket API
227+
(JSR-356), Jetty, Undertow, Reactor Netty, and RxNetty.
228+
229+
On the server side, declare a `WebSocketHandlerAdapter` and then simply add
230+
mappings to `WebSocketHandler`-based endpoints:
231+
232+
[source,java,indent=0]
233+
[subs="verbatim,quotes"]
234+
----
235+
@Bean
236+
public HandlerMapping webSocketMapping() {
237+
Map<String, WebSocketHandler> map = new HashMap<>();
238+
map.put("/foo", new FooWebSocketHandler());
239+
map.put("/bar", new BarWebSocketHandler());
240+
241+
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
242+
mapping.setUrlMap(map);
243+
return mapping;
244+
}
245+
246+
@Bean
247+
public WebSocketHandlerAdapter handlerAdapter() {
248+
return new WebSocketHandlerAdapter();
249+
}
250+
----
251+
252+
On the client side create a `WebSocketClient` for one of the supported libraries
253+
listed above:
254+
255+
[source,java,indent=0]
256+
[subs="verbatim,quotes"]
257+
----
258+
WebSocketClient client = new ReactorNettyWebSocketClient();
259+
client.execute("ws://localhost:8080/echo"), session -> {... }).blockMillis(5000);
260+
----
261+
262+
263+
264+
265+
220266
[[web-reactive-getting-started]]
221267
== Getting Started
222268

@@ -226,18 +272,22 @@ when the method returns; implies a synchronous, non-blocking controller method.
226272

227273
The
228274
https://github.com/bclozel/spring-boot-web-reactive#spring-boot-web-reactive-starter[Spring Boot Web Reactive starter]
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
231-
writing `@Controller` classes. By default it runs on Tomcat but the dependencies can
232-
be changed as usual with Spring Boot to switch to a different runtime.
233-
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.
275+
available via http://start.spring.io is the fastest way to get started.
276+
It does all that's necessary so you to start writing `@Controller` classes
277+
just like with Spring MVC. Simply go to http://start.spring.io, choose
278+
version 2.0.0.BUILD-SNAPSHOT, and type reactive in the dependencies box.
279+
By default the starter runs with Tomcat but the dependencies can be changed as usual with Spring Boot to switch to a different runtime.
280+
See the
281+
https://github.com/bclozel/spring-boot-web-reactive#spring-boot-web-reactive-starter[starter]
282+
page for more details and instruction
283+
284+
There is no Spring Boot Starter for the functional programming model yet but
285+
it's very easy to try it out. See the next section on "Manual Bootstrapping".
236286

237287
[[web-reactive-getting-started-manual]]
238288
=== Manual Bootstrapping
239289

240-
This section outlines the steps to get up and running without Spring Boot.
290+
This section outlines the steps to get up and running manually.
241291

242292
For dependencies start with `spring-web-reactive` and `spring-context`.
243293
Then add `jackson-databind` and `io.netty:netty-buffer`
@@ -250,7 +300,7 @@ Lastly add the dependencies for one of the supported runtimes:
250300
* RxNetty -- `io.reactivex:rxnetty-common` and `io.reactivex:rxnetty-http`
251301
* Undertow -- `io.undertow:undertow-core`
252302

253-
For the **annotation-based programming model**, bootstrap code start with:
303+
For the **annotation-based programming model** bootstrap with:
254304
[source,java,indent=0]
255305
[subs="verbatim,quotes"]
256306
----
@@ -260,15 +310,16 @@ HttpHandler handler = DispatcherHandler.toHttpHandler(context); // (2)
260310

261311
The above loads default Spring Web Reactive config (1), then creates a
262312
`DispatcherHandler`, the main class driving request processing (2), and adapts
263-
it to `HttpHandler`, the lowest level Spring abstraction for reactive HTTP request handling.
313+
it to `HttpHandler` -- the lowest level Spring abstraction for reactive HTTP request handling.
264314

265-
For the **functional programming model**, bootstrap code start with:
315+
For the **functional programming model** bootstrap as follows:
266316
[source,java,indent=0]
267317
[subs="verbatim,quotes"]
268318
----
269319
ApplicationContext context = new AnnotationConfigApplicationContext(); // (1)
270320
context.registerBean(FooBean.class, () -> new FooBeanImpl()); // (2)
271321
context.registerBean(BarBean.class); // (3)
322+
272323
HttpHandler handler = WebHttpHandlerBuilder
273324
.webHandler(RouterFunctions.toHttpHandler(...))
274325
.applicationContext(context)
@@ -279,7 +330,7 @@ The above creates an `AnnotationConfigApplicationContext` instance (1) that can
279330
of the new functional bean registration API (2) to register beans using a Java 8 `Supplier`
280331
or just by specifying its class (3). The `HttpHandler` is created using `WebHttpHandlerBuilder` (4).
281332

282-
**Common to both** annotation and functional flavors, an `HttpHandler` can then be installed in each supported runtime:
333+
The `HttpHandler` can then be installed in one of the supported runtimes:
283334

284335
[source,java,indent=0]
285336
[subs="verbatim,quotes"]
@@ -290,10 +341,7 @@ HttpServlet servlet = new ServletHttpHandlerAdapter(handler);
290341
291342
// Reactor Netty
292343
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
293-
HttpServer.create(host, port)
294-
.newHandler(adapter)
295-
.doOnNext(c -> System.out.println("Server listening on " + c.address())).block()
296-
.onClose().block();
344+
HttpServer.create(host, port).newHandler(adapter).onClose().block();
297345
298346
// RxNetty
299347
RxNettyHttpHandlerAdapter adapter = new RxNettyHttpHandlerAdapter(handler);
@@ -308,10 +356,12 @@ server.start();
308356

309357
[NOTE]
310358
====
311-
For Servlet runtimes you can use the `AbstractAnnotationConfigDispatcherHandlerInitializer`,
312-
which as a `WebApplicationInitializer` is auto-detected by Servlet containers
313-
and it registers for you the `ServletHttpHandlerAdapter` shown above.
314-
Only implement one method to point to your Spring Java configuration classes.
359+
For Servlet containers especially with WAR deployment you can use the
360+
`AbstractAnnotationConfigDispatcherHandlerInitializer` which as a
361+
`WebApplicationInitializer` and is auto-detected by Servlet containers.
362+
It takes care of registering the `ServletHttpHandlerAdapter` as shown above.
363+
You will need to implement one abstract method in order to point to your
364+
Spring configuration.
315365
====
316366

317367
[[web-reactive-getting-started-examples]]

0 commit comments

Comments
 (0)