The Reactive Framework in Spring MVC: a tale of two tails.


In 2017 Spring framework 5 introduced a new reactive, non-blocking, asynchronous
 web framework called Spring WebFlux.
I attended in September 2018 the SpringOne conference in Washington DC where various Spring committers gave presentations on this topic - among others.
This new framework does not replace the classic servlet based web framework spring-mvc, but gives the developer the choice to select one or the other depending on the solution he is looking for.




As Roosen Stoyanchev says in this great article ( Servlet vs Reactive, choosing the right stack): the reactive programming is about bringing asynchronicity in applications.
Traditionally Java developers needed to use a number of threads and thread pools to achieve asynchronicity, but that approach does not scale well. There is a misconception in Java that we need a great number of threads to obtain concurrency.
That is not the case anymore for Java (there are other languages that are already using this approach): we can obtain concurrency with a few threads by using HTTP sockets and pushing chunks of data through the sockets (the mechanism is called event-loop and the idea was made popular by node.js ).
Spring 5's spring-webflux uses the event-loop approach to provide asynchronicity.

BTW this post is based on Roosen's presentation on SpringOne 2018:  Guide to "Reactive" for Spring MVC developers.
                                                     


What is the main difference between spring-mvc and spring-webflux ? spring-mvc uses a thread pools
while spring-webflux uses event-loop mechanism, but both mechanisms supports commonly annotations like @Controller.

Typically on a blocking IO framework (Spring MVC Servlet , Thymeleaf, etc.) there is an assumption that after we receive a request there is some kind of processing (read, write) where we need to wait for the result of that operation before continuing with the next one.
With this new approach we can handle the request "reactively",  using the react librairies, do some sort of handling and then get back to the controller.
You will understand this idea better when you see the examples.

From the documentation from Spring Webflux :
"Reactor is the reactive library of choice for Spring WebFlux. It provides the Mono and Flux API types to work on data sequences of 0..1 (Mono) and 0..N (Flux) through a rich set of operators aligned with the ReactiveX vocabulary of operators. Reactor is a Reactive Streams library and, therefore, all of its operators support non-blocking back pressure. Reactor has a strong focus on server-side Java. It is developed in close collaboration with Spring."

Reactive Client for HTTP 

Let's start with a simple example, a client that makes a call to a backend (you'll find the link for the GitHub repository of the project at the end of this post). 



In this example we're using the classic RestTemplate class to call the url on the backend, the code is easy, you may already used it hundred of times, but if we need to do something more specific (like calling different backends in parallel), then the React library is the solution. As Roosen says in his presentation: "it is not that the RestTemplate became less easy in time, it's the things that we do became quite different".
This is the result:




Let's try the same example with the React library:




As you can see we're creating a WebClient with the same url. Once we create the client, we can call the HTTP methods (in this case get()), then we define the URI and we call the retrieve() method. Finally we decode the response to a Mono (which is used to retrieve a single value while Flux  is used for multiple values) of Player.



Wait, what happened here? This code is not doing anything, it is not calling the endpoint we're asking for. Why? This code is only creating a promise of a Mono but it's not going to call the endpoint until we subscribe, let's try again with the subscribe() method



then we see it is calling the endpoints:


Cool, what's next? To make the best use of the concurrency model, let's try to collect all the Mono's, wait for them to complete and then do something with that - unleashing the power of the Stream library 👊.



We can also start calling the Reactor's operators to tell the code to wait until all the Mono's have completed (the line with Mono.when() ).


As you can see all of the calls kicked-off at the same time, and then they all run concurrently, and we get back the result. The time that it takes to complete all the threads (463 ms. ) it's the same time that takes to complete just one of them --> because they run concurrently.
Let's add two more players and check what happens with the threads:



Reactor Netty (the default server that comes with spring-webflux) comes with 4 threads, it will use only those threads to manage all the calls, it will not add more threads every time we make a new call. That is the non-blocking concurrency model we're trying to explain. In our example the #4 thread calls two different players. 

Now let's dig into the Reactor library to change that code



Now we're using the Flux class to iterate, and then we change the map method into a flatmap: this last method is useful to not only create the Promise of a Flux of Player's but also to subscribe to that endpoint and actually calling it, and then transforming that call into that Flux of Player's which is what we need here. Every time you need to call an endpoint to get a Mono or a Flux you should use  flatmap.
You can play with the library as I do, let's wait for all Player's and block the last one. 

This is what we get


One important thing about our WebClient here: the retrieve() operation gives us a straight path to the body of the response, but if we need to do something before transforming the body, we can use exchange()



The exchange() method gives us access to the Response before the body has been read. Then you can peek at the response, ask for the statusCode, the headers, etc. before dealing with the body.

One more very interesting thing we can do is create nested HTTP calls:


The first flatmap operation is very similar to what we have done before in another example, but this time after decoding the Player object we're going to make another asynchronous call using again  flatmap , this time to get his position in the field. As you can see in the code, it is very easy to do it. Again, you don't need to handle a lot of threads although all the calls are done in a concurrently manner.


Here we're not only asking for the players, but as soon as those calls come back with the information a new HTTP call goes, this time to ask for the position for that particular player, then we can combine the results.  The elapsed time is very similar to the one we had when we were calling only for the players.

Is there anything else than the WebClient for React? Oh yes there is. There are a lot of Reactive libraries that can be used to help you build your application, creating pipelines of different modules that use asynchronous calls and Reactive streams.
  1. We can use the WebClient from a typical Spring MVC Controller, form the server side. If you're dealing with Flux and Mono in your web client, you should also be able to return those objects from your controller's methods.   
  2. We can use SQL databases in a non-blocking asynchronous manner: that project is called R2DBC (Reactive relational database connectivity) and it's a fully reactive JDBC alternative so you can access your relational database in a reactive way. There is already an implementation of PostgreSQL for R2DBC out of the box. (there is also support for Spring Data R2DBC)
  3. We can also use NoSQL databases like Cassandra, MongoDB or CouchBase in a reactive manner. 
  4. Finally there is a new application network binary protocol for Reactive Streams: RSocket, it was created by engineers from Facebook, Netifi and Pivotal amongst others and it was designed to work well with reactive-style applications (non-blocking & asynchronous behaviour). Here is an interesting article on RSocket.

Here is the example on GitHub  and some docs.


Enjoy !





Comments

Popular Posts