Web Reactive Programming: Spring WebFlux
At Moove It we love keeping up with the latest developments across a variety of technologies. In this article, we’ll introduce you to one of the exciting programming tools that have been released recently – Spring WebFlux – by first giving some useful background, then explaining the tool itself, and finishing with an example to help you get started. Try to follow along with the example while we explain it. Let’s dive in!
Reactive Programming is, as its name implies, a programming paradigm that promotes an asynchronous, non-blocking, event-driven approach to data processing. “Reactive” models in programming are built around the publisher-subscriber pattern (observer pattern), where the “publishers” are sent data from all parts of the application to then emit out to any “subscribers” that are listening, which in turn handle the data as needed. As such, publishers are the backbone of Reactive Programming, and the code is inherently asynchronous from the ground up.
Blocking vs non-blocking (async) request processing
Blocking request processing
In traditional MVC applications, when a request comes to the server, a servlet thread is created. It delegates the request to worker threads for I/O operations such as database access. During the time worker threads are busy, the servlet thread (request thread) remains in a waiting status and thus is blocked. This can also be called “synchronous request processing.”
Given that a server can have a finite number of request threads, this approach limits its capacity to process effectively at maximum load.
Non-blocking request processing
In non-blocking (or asynchronous) request processing, threads do not have a waiting state, and generally, there is only one primary request thread, with a separate thread pool (generally a small number of threads) for delegating work to.
All incoming requests (events) arrive with a callback which will be called at some later time. The request thread delegates any incoming requests to the thread pool, which in turn delegates individual requests to individual threads within the pool. The delegated thread then uses the appropriate handler for the event it just received.
When the handler function is complete, one of the threads from the pool collects the response and passes it to the callback function that the original event arrived with.
The non-blocking nature of threads helps in scaling the performance of the application, and the small number of threads means less memory utilization as well as less context switching.
Reactive Streams API
The new Reactive Streams API was created by engineers from several organizations including Netflix, Pivotal, RedHat, Twitter, and Oracle, among others, and forms part of Java 9. It defines four interfaces:
Publisher: emits events to Subscribers. A Publisher can serve multiple Subscribers.
Subscriber: receives and processes events emitted by a Publisher. No events will be received until Subscription#request(long) is called to signal the request.
Subscription: Defines a one-to-one relationship between a Publisher and a Subscriber. It can only be used once by a single Subscriber. It is used to both signal a desire for data and cancels any current requests, which aids resource cleanup.
Processor: Represents a processing stage consisting of both a Subscriber and Publisher and obeys the contracts of both.
Now that you’ve got some background, let’s talk about WebFlux.
What is Spring WebFlux?
Spring WebFlux is a parallel version of Spring MVC and supports fully non-blocking reactive streams. It supports the backpressure concept and uses Netty as a built-in server to run reactive applications.
Spring WebFlux uses Project Reactor as a reactive library. Reactor is a Reactive Streams library, so its operators support non-blocking backpressure.
Spring WebFlux mainly uses two Publishers:
- Mono: Returns 0 or 1 element.
- Flux: Returns 0…N elements. A Flux can be endless, meaning that it can keep emitting elements forever. Also it can return a sequence of elements and then emit a completion event when it has returned all of its elements.
In Spring WebFlux, we call reactive APIs/functions that return Monos or Fluxes, which means your controllers will return the same Monos and Fluxes. When you invoke an API that returns a Mono or a Flux, it will come back immediately. The results of the function call will be delivered to you through the Mono or Flux when they become available.
It’s important to mention that to build a truly non-blocking application, we must aim to design all of its components as non-blocking, including the client, controller, middleware services, and even the database. If any component blocks requests, we have not achieved our goal.
WebFlux supports two programming models:
- Annotation-based reactive components
- Functional routing and handling
Today we will focus on the annotation-based approach.
We will build a REST API for publishing and retrieving resources (in our case “Books”) using RestController to make it fully non-blocking. We will also use MongoDB as our database.
1. Maven dependencies
We have to include spring-boot-starter-webflux and spring-boot-starter-data-mongodb-reactive dependencies.
Spring WebFlux supports annotation-based configurations just like the Spring Web MVC framework.
Spring boot application
4. REST Controller
Let’s create endpoints in our controller that publish:
- A single Book resource. We will use a Mono of type Book because it will emit at most 1 element.
- The collection resource of all Books. We will use a Flux of type Book because it will emit 0..n elements.
5. DAO repository
BookRepository can be any repository data that supports non-blocking reactive streams. We will use MongoDB.
Start the application by running WebfluxFunctionalApp and check requests and responses.
- HTTP POST http://localhost:8080/create
- HTTP POST http://localhost:8080/create
- HTTP GET http://localhost:8080/
Notice that we are testing the API with Postman which is a blocking client. It will display the result only when It has collected the response from both books.
To verify the non-blocking response feature, hit the URL in the browser directly. The results will appear one at a time when they are available, in the form of events (text/event-stream). To view the results better, add a delay to the controller API.
Both Spring MVC and Spring WebFlux support a client-server architecture but differ in their concurrency models. In Spring MVC it is assumed that applications can block the current thread, while in WebFlux threads are non-blocking by default.
Reactive and non-blocking applications do not inherently run faster than blocking applications, but rather provide scaling benefits with a small, fixed number of threads and smaller memory requirements.