Spring WebFlux: Initiation
Spring Web Flux, is the Spring module for reactive programming. This will basically allow us to perform asynchronous invocations to microservices. Here you can find all the official information. What we will see in this example will be Spring’s implementation of the Reactive Streams specification through the Reactor library, more info here and here. And we have to make use of a 3.1+ servlet container such as Netty, Tomcat, Jetty, or Undertow.
To begin with, we will give a little explanation about reactive programming, this is nothing more than a new programming paradigm oriented to data flows (Streams) and event propagation as opposed to blocking waiting for a response. In this reactive programming there are a couple of key concepts:
- Publishers. They are those that issue the data stream, i.e. our services.
- Subscriber. They are those who are subscribed and receive the data synchronously, the clients/websites.
As we have said we are going to see its operation with a more or less practical example. And it will be based on the idea that we need to implement a page that shows the incidents in different servers. These servers have a microservice that shows information about them. With the normal use of Spring MVC, we would make different calls sequentially and it would take the sum of the time associated with each of the responses. With Spring WebFlux we will take as long as the response of the slowest service takes.
The example will consist of two projects, the first one will be the dummy microservice that gives the information about the system. And the second one will be the client that receives the information from the previous microservices, invoked several times but with different parameters. In both, to be able to use WebFlux and all the associated classes as it is normal in Spring we will simply have to add a library and nothing of configuration. This is spring-boot-starter-webflux.
In the end, to be able to compare the performance we will create two different methods one that will make use of the reactive streams and another one that will not. Although in this post we will only show the code associated with the Spring WebFlux module. The first microservice, the dummy that shows the information, will be composed by a method that instead of returning a list of objects, in this case, incidents, we will return an object of type Flux.
What is an object of type Flux? Spring through Reactor provides two objects that allow us to pass other objects asynchronously, these are Mono and Flux. Mono allows us to send one or no objects and Flux allows us to send from none to an indeterminate list of objects. That is to say that if we want a single object to respond we will use Mono and for a set, we will use Flux.
Flux.just is the typical utility method for creating objects. The delaySequence method will allow us to add some latency to our service and give it a more realistic appearance. In the method without using the reactive API, we will use a Thread.sleep(3000). This way we will be able to measure the efficiency in the final comparison.
Now we will create the client, composed by service and controller. The service will make the different calls to the microservices of each of the servers from which we want to obtain information. And the controller will collect that information and pass it to the view to show it to the user. Next, we show the service.
In order to invoke an endpoint asynchronously, we must use the WebClient object. Its use is similar to other HTTP clients that we have seen in other posts, such as Feign or HTTPClient. In this case, we will do it in the following way:
- get() will allow us to make a GET invocation, but we can use any other HTTP method. All of them will give us access to a set of methods, for example cookie(), which will allow us to modify the invocation to be made.
- retrieve() will allow us to get the response and will also make available to us another set of methods to handle that response.
Finally with Flux.merge we will be able to unify the answers of the different invocations. Something similar to an addAll if we were using List type objects and blocking invocations.
Now we will only have the client controller where we will receive the complete list and we will send it to the view. In it, we will also show how long it has taken to execute the method.
As you can see in the previous code snippet, the API provides us with different methods that allow us to deal with Mono and Flux objects. With collectList we can pass it to an object of type Mono<List<?>> and with block we can make it wait for the invocation until we have the complete list and transform it finally to a list of objects. But there are many more methods that allow us to transform them into other types of objects, or to treat the data without needing the confirmation of having obtained all the results.
Finally a small sample of the times of a blocking execution using List objects and another asynchronous execution, using Flux objects. And doing in both cases the same number of invocations:
IncidenceController : incidence ListFlux : 3392 miliseconds
IncidenceController : incidence List : 12088 miliseconds
Spring WebFlux opens up a wide range of possibilities in all areas of programming. Starting with web programming and front-end applications to the application in monitoring systems, in which the improvement in response times is fundamental. If you want to see all the code, you have it here.