This section provides basic information on the reactive programming support for Web applications in Spring Framework 5.
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 "Notes on Reactive Programming" by Dave Syer.
Spring Framework 5 embraces
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 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
"Understanding Reactive Types"
by Sebastien Deleuze.
Spring Framework 5 includes a new spring-web-reactive
module. The module contains support
for reactive HTTP and WebSocket clients as well as for reactive server web applications
including REST, HTML browser, and WebSocket style interactions.
On the server-side the new reactive module supports 2 distinct programming models:
@Controller
and the other annotations supported also with Spring MVC
Both programming models are executed on the same reactive foundation that adapts
non-blocking HTTP runtimes to the Reactive Streams API. The diagram
below shows the server-side stack including traditional, Servlet-based
Spring MVC on the left from the spring-web-mvc
module and also the
reactive stack on the right from the spring-web-reactive
module.
The new reactive stack can run on Servlet containers with support for the
Servlet 3.1 Non-Blocking IO API as well as on other async runtimes such as
Netty and Undertow. Each runtime is adapted to a reactive
ServerHttpRequest
and ServerHttpResponse
exposing the body of the
request and response as Flux<DataBuffer>
, rather than
InputStream
and OutputStream
, with reactive backpressure.
REST-style JSON and XML serialization and deserialization is supported on top
as a Flux<Object>
, and so is HTML view rendering and Server-Sent Events.
The same @Controller
programming model and the same annotations used in Spring MVC
are also supported on the reactive side. The main difference is that the framework
contracts underneath — i.e. HandlerMapping
, HandlerAdapter
, are
non-blocking and operate on the reactive ServerHttpRequest
and ServerHttpResponse
rather than on the HttpServletRequest
and HttpServletResponse
.
Below is an example with a reactive controller:
@RestController public class PersonController { private final PersonRepository repository; public PersonController(PersonRepository repository) { this.repository = repository; } @PostMapping("/person") Mono<Void> create(@RequestBody Publisher<Person> personStream) { return this.repository.save(personStream).then(); } @GetMapping("/person") Flux<Person> list() { return this.repository.findAll(); } @GetMapping("/person/{id}") Mono<Person> findById(@PathVariable String id) { return this.repository.findOne(id); } }
The functional programming model uses Java 8 lambda style routing and request
handling instead of annotations. The main API contracts are functional interfaces named
RouterFunction
and HandlerFunction
. They are simple but powerful building blocks
for creating web applications. Below is an example of functional request handling:
PersonRepository repository = ... RouterFunctions .route(GET("/person/{id}").and(accept(APPLICATION_JSON)), request -> { int personId = Integer.valueOf(request.pathVariable("id")); Mono<ServerResponse> notFound = ServerResponse.notFound().build(); return repository.findOne(personId) .then(person -> ServerResponse.ok().body(Mono.just(person), Person.class)) .otherwiseIfEmpty(notFound); }) .andRoute(GET("/person").and(accept(APPLICATION_JSON)), request -> ServerResponse.ok().body(repository.findAll(), Person.class)) .andRoute(POST("/person").and(contentType(APPLICATION_JSON)), request -> ServerResponse.ok().build(repository.save(request.bodyToMono(Person.class))));
For more on the functional programming model see the M3 release blog post.
Spring Framework 5 includes a functional, reactive WebClient
that offers a fully
non-blocking and reactive alternative to the RestTemplate
. It exposes network
input and output as a reactive ClientHttpRequest
and ClientHttpRespones
where
the body of the request and response is a Flux<DataBuffer>
rather than an
InputStream
and OutputStream
. In addition it supports the same reactive JSON, XML,
and SSE serialization mechanism as on the server side so you can work with typed objects.
Below is an example of using the WebClient
which requires a ClientHttpConnector
implementation to plug in a specific HTTP client such as Reactor Netty:
WebClient client = WebClient.create(new ReactorClientHttpConnector()); ClientRequest<Void> request = ClientRequest .GET("http://example.com/accounts/{id}", 1L) .accept(APPLICATION_JSON) .build(); Mono<Account> account = client .exchange(request) .then(response -> response.bodyToMono(Account.class));
![]() | Note |
---|---|
The |
The spring-core
module provides reactive Encoder
and Decoder
contracts
that enable the serialization of a Flux
of bytes to and from typed objects.
The spring-web
module adds JSON (Jackson) and XML (JAXB) implementations for use in
web applications as well as others for SSE streaming and zero-copy file transfer.
For example the request body can be one of the following way and it will be decoded automatically in both the annotation and the functional programming models:
Account account
— the account is deserialized without blocking before the controller is invoked.
Mono<Account> account
— the controller can use the Mono
to declare logic to be executed after the account is deserialized.
Single<Account> account
— same as with Mono
but using RxJava
Flux<Account> accounts
— input streaming scenario.
Observable<Account> accounts
— input streaming with RxJava.
The response body can be one of the following:
Mono<Account>
— serialize without blocking the given Account when the Mono
completes.
Single<Account>
— same but using RxJava.
Flux<Account>
— streaming scenario, possibly SSE depending on the requested content type.
Observable<Account>
— same but using RxJava Observable
type.
Flowable<Account>
— same but using RxJava 2 Flowable
type.
Flux<ServerSentEvent>
— SSE streaming.
Mono<Void>
— request handling completes when the Mono
completes.
Account
— serialize without blocking the given Account; implies a synchronous, non-blocking controller method.
void
— specific to the annotation-based programming model, request handling completes
when the method returns; implies a synchronous, non-blocking controller method.
The Spring Framework 5 spring-web-reactive
module includes reactive WebSocket
client and server support. Both client and server are supported on the Java WebSocket API
(JSR-356), Jetty, Undertow, Reactor Netty, and RxNetty.
On the server side, declare a WebSocketHandlerAdapter
and then simply add
mappings to WebSocketHandler
-based endpoints:
@Bean public HandlerMapping webSocketMapping() { Map<String, WebSocketHandler> map = new HashMap<>(); map.put("/foo", new FooWebSocketHandler()); map.put("/bar", new BarWebSocketHandler()); SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); mapping.setUrlMap(map); return mapping; } @Bean public WebSocketHandlerAdapter handlerAdapter() { return new WebSocketHandlerAdapter(); }
On the client side create a WebSocketClient
for one of the supported libraries
listed above:
WebSocketClient client = new ReactorNettyWebSocketClient(); client.execute("ws://localhost:8080/echo"), session -> {... }).blockMillis(5000);
The
Spring Boot Web Reactive starter
available via http://start.spring.io is the fastest way to get started.
It does all that’s necessary so you to start writing @Controller
classes
just like with Spring MVC. Simply go to http://start.spring.io, choose
version 2.0.0.BUILD-SNAPSHOT, and type reactive in the dependencies box.
By default the starter runs with Tomcat but the dependencies can be changed as usual with Spring Boot to switch to a different runtime.
See the
starter
page for more details and instruction
There is no Spring Boot Starter for the functional programming model yet but it’s very easy to try it out. See the next section on "Manual Bootstrapping".
This section outlines the steps to get up and running manually.
For dependencies start with spring-web-reactive
and spring-context
.
Then add jackson-databind
and io.netty:netty-buffer
(temporarily see SPR-14528) for JSON support.
Lastly add the dependencies for one of the supported runtimes:
org.apache.tomcat.embed:tomcat-embed-core
org.eclipse.jetty:jetty-server
and org.eclipse.jetty:jetty-servlet
io.projectreactor.ipc:reactor-netty
io.reactivex:rxnetty-common
and io.reactivex:rxnetty-http
io.undertow:undertow-core
For the annotation-based programming model bootstrap with:
ApplicationContext context = new AnnotationConfigApplicationContext(DelegatingWebReactiveConfiguration.class); // (1) HttpHandler handler = DispatcherHandler.toHttpHandler(context); // (2)
The above loads default Spring Web framework configuration (1), then creates a
DispatcherHandler
, the main class driving request processing (2), and adapts
it to HttpHandler
— the lowest level Spring abstraction for reactive HTTP request handling.
For the functional programming model bootstrap as follows:
ApplicationContext context = new AnnotationConfigApplicationContext(); // (1) context.registerBean(FooBean.class, () -> new FooBeanImpl()); // (2) context.registerBean(BarBean.class); // (3) HttpHandler handler = WebHttpHandlerBuilder .webHandler(RouterFunctions.toHttpHandler(...)) .applicationContext(context) .build(); // (4)
The above creates an AnnotationConfigApplicationContext
instance (1) that can take advantage
of the new functional bean registration API (2) to register beans using a Java 8 Supplier
or just by specifying its class (3). The HttpHandler
is created using WebHttpHandlerBuilder
(4).
The HttpHandler
can then be installed in one of the supported runtimes:
// Tomcat and Jetty (also see notes below) HttpServlet servlet = new ServletHttpHandlerAdapter(handler); ... // Reactor Netty ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler); HttpServer.create(host, port).newHandler(adapter).onClose().block(); // RxNetty RxNettyHttpHandlerAdapter adapter = new RxNettyHttpHandlerAdapter(handler); HttpServer server = HttpServer.newServer(new InetSocketAddress(host, port)); server.startAndAwait(adapter); // Undertow UndertowHttpHandlerAdapter adapter = new UndertowHttpHandlerAdapter(handler); Undertow server = Undertow.builder().addHttpListener(port, host).setHandler(adapter).build(); server.start();
![]() | Note |
---|---|
For Servlet containers especially with WAR deployment you can use the
|
You will find code examples useful to build reactive Web application in the following projects:
spring-functional
branch is a Spring 5 functional, Java 8 lambda-style application
StepVerifier