Wednesday 26 September 2018

Introducing Spring Webflux

Posted by Naveen Katiyar On 06:21 1 comment
In this article we are going to discuss on different choices which are provided by Spring 5 for Reactive and Async Concurrency model.I quite strongly believe, before we embrace something new, we should be aware of the differences between choices and how it connects to what we have been already doing. In my previous articles on this topic, I have tried to explain what we already have regarding concurrency model and how concurrency model has changed in Spring over the years with several updates in Servlet API.I would strongly recommend to read my previous articles on this topic, so that this article will make more sense.

Let’s try to figure out what was the reason to provide two different non blocking stacks in Spring 5.Basically Spring 5 provides  following two stacks for doing things in Async and non-blocking way:
  1. Spring MVC (Servlet Stack)
  2. Spring Webflux(Reactive Stack)

Spring MVC(Servlet Stack)

With the introduction of Servlet 3.1, Spring MVC could achieve non-blocking behavior.But as Servlet API contains several interfaces which are still blocking(may be because of support for backward compatibility),there was always chance of accidently using blocking API in application which was intended to be developed as Non-blocking.In such scenario,usage of blocking API will certainly bring down the application sooner or later. Let’s discuss one of the such scenario with below code snippet:

void onWritePossible(){
 try{
    //some logic here
 }catch(Exception e){
    response.sendError(500); ----> sendError() is a blocking API
 }
}

To explain above in Spring MVC context, using container managed error page is blocking.Let’s take a look at below code on my repo-


@Controller
public class MyErrorController implements ErrorController {
   @RequestMapping(path = "/error")
   public String greeting() {
      return "myerror";
   }
   @Override
   public String getErrorPath() {
      return "/error";
   }
}
Whenever some error occurs in a Spring application, container would invoke /error page and ‘myerror’ page would be rendered in a blocking way. Off course, we have ways to handle such things but are definitely error prone. To summarize, this is error prone, because application has access to Servlet Object, which has both blocking and non-blocking operations as shown below:

Online Java Papers : Spring Webflux

                                                        Flow Of Events

Online Java Papers : Spring Webflux                                                
                                                
So even though, we have ways in Spring 5 MVC to write completely non blocking code, The need was felt to have a stack in which there are no chances by which underlying blocking API’s could be used which means Servlet API is not directly exposed to application.This brings us to introduce Spring Reactive stack i.e. Spring Webflux.


Spring Webflux(Reactive Stack)

Spring webflux is a completely non-blocking reactive framework and it is indeed different than what we have in Spring MVC.  So,what does it take to not block in Spring webflux:

  • Event Loop at the core.
  • Event driven architecture,message passing
  • Means to compose async logic through Reactive Streams API
  • Backpressure

As we can see in below diag, Spring Webflux does not directly use Servlet instead use Spring Web API which include Reactor Streams.                                     

                                           Online Java Papers : Spring Webflux

Purpose of this tutorial series is to demonstrate the evolution of Servlet/Spring from blocking to Non-blocking paradigm, So I am not going in details of Spring Webflux in this tutorial.But still I am going to introduce a sample Spring boot application using Spring webflux.

One point which we should notice in above diagram is that Spring webflux is Servlet Container agnostic. Spring Webflux works on Servlet Container and also on Netty through Reactor Netty Project.

In my Spring boot application, I have a dependency of Webflux as spring-boot-starter-webflux and at server startup it says that application is ready with Netty.

[reactor-http-nio-1] 18:33 BlockingNettyContext: Started HttpServer on /0:0:0:0:0:0:0:0:8080
[restartedMain] 18:33 NettyWebServer: Netty started on port(s): 8080

In same application, if we use dependency to spring-boot-starter-web then logs would be printed as below:
[restartedMain] 23:56 TomcatWebServer: Tomcat started on port(s): 8080 (http) with context path ''

So without any code change, we can run Spring Webflux application as Spring MVC application.But vice-versa is not true as Spring MVC application could be using HttpServletRequest/Response which are not available in Spring Webflux runtime.

I have created same type of service which we used in earlier article using webflux as below:

@GetMapping(value = "/reactiveService")
public Mono<String> reactiveService(){
   logger.debug("reactiveService Request processing started");
   return webClient.get().uri("/sleep/1000")
          .retrieve().bodyToMono(Boolean.class)
          .doOnNext(response->{ logger.debug("reactive service");})
          .then(Mono.just("reactiveService"));

}

I would leave this for readers to compare the performance between this API and asyncNonBlockingRequestProcessing API as both are using non-blocking paradigm but underlying stack is different for both API’s.

Thank you for reading my article and I hope It would have helped a bit in understanding about reactive in Spring/Servlet context.

Source code for reactiveService could be found below: