Geek Culture
Published in

Geek Culture

An In-Depth Look at Spring WebFlux

When dealing with large amount of concurrent users, Traditional Spring MVC based applications tend to use a high number of threads and consume a lot of resources. Servlet 3.1 did brought in Non-blocking IO (NIO) support on top of Servlet 3.0, however, using it requires a deviation from from the rest of the Servlet API where contracts are synchronous (Servlet, Filter)or blocking (getParameter, getPart).

Adding to that, the introduction of frameworks establishing a fully non blocking contract on HTTP layer (such as Netty ) served as a starting point for developing an alternative to Spring Web Stack.

Spring WebFlux -Introduction

Spring WebFlux was introduced in Spring 5 as a new reactive fully non-blocking framework. It internally uses Reactor project, thus, supports Reactive Streams Specification and runs on such servers as Netty.

In this episode, we will go through Spring WebFlux features, in particular functional endpoints, its core components and processing in depth. I highly recommend reading Visiting Reactor Netty , it would make the learning easier as Spring WebFlux default’s embedded server is Reactor Netty.

Also, a basic understanding of Spring MVC would be a plus.

By the end of this article, you would be able to migrate easily if needed from Spring MVC to The New Reactive Web framework.

Spring WebFlux: a functional framework

Spring WebFlux comes with supports to functional endpoints alongside with annotated controllers. The functional web framework introduces a new programming model where we use functions to route and handle requests.

As a contrary to the annotation-based model where Spring MVC framework scans the classpath for @Controller annotated classes, and register looks up methods that are annotated with @RequestMapping, The functional web framework use HandlerFunction and RouterFunctions.

For example using the Spring MVC you would define your controller as follows:

Now let’s look at the functional equivalent.

Yes, less annotations which means less processing.

The high level process is as follows: when an Http request comes at the Server, this request is delegated to the RouterFunction to resolve an appropriate HandlerFunction to handle the Httprequest and serves a respond to it. The RouterFunction is a substitute of @RequestMapping annotation and the HandlerFunction is the implementation of how the request will be handled.

With a functional approach, you are more concerned with how to implement your business logic than exposing the endpoints.

Spring WebFlux Core Classes

Throughout this section, we will examine Spring WebFlux Core components.

The WebHandler class

WebHandler is a contract to handle a web request. As shown below, it’s handle function is invoked to process a web server exchange.

The HttpHandler class

HttpHandler is lowest level contract for reactive HTTP request handling that serves as a common denominator across different runtimes.

The HttpWebHandlerAdapter class

HttpWebHandlerAdapter is Default adapter of WebHandler to the HttpHandler contract.

As shown on the below code snippet, it creates and configures a DefaultServerWebExchange and then invokes the target WebHandler (DispatcherHandler).

The DispatcherHandler class

DispatcherHandler is similar to DispatcherServlet in Spring MVC and is responsible for handling http requests.

Through its initialisation phase, it will discover special beans to which tasks would be delegated based on the received requests.

You can find below the above objetcs and their respective responsibility:

  • HandlerMapping: Map a request to a handler object.
  • HandlerAdapter: Contract that decouples the DispatcherHandler from the details of invoking a handler and makes it possible to support any handler type.
  • HandlerResultHandler: Process the HandlerResult, usually returned by a HandlerAdapter.

The handling logic is actually implemented in the DispatcherHandler’s handle method shown below.

This basically happens:

  • For each mappings tries to get an appropriate handler, the semantic here is first found wins. If no handler can be found an exception is thrown.
  • Next, invoke handler will tries to resolve a HandlerAdapter that supports the current handler. If not found an error is sent downstream.
  • Finally the result is handled using an appropriate HandlerResult object.

The RouterFunctionMapping Class

RouterFunctionMapping is a HandlerMapping implementation that supports RouterFunctions. As shown below, if no RouterFunction is provided at construction time, this mapping will examine the application context and collect all the beans of type RouterFunction in order.

Given an http request (encapsulated in a ServerWebExchange), getHandler is actually responsible for resolving a handler for this request.

It will first invoke getHandlerInternal to do a look up and returning an empty Mono if no specific one is found. It basically checks the RouterFunction (that may be composite) if the request can be routed and if no match has been found return an empty result that would actually terminate the inner flux and next RouterFunctionMapping would be fetched.

The HandlerAdapter class

HandlerAdapter is a contract that decouples the DispatcherHandler from the details of invoking a handler and makes it possible to support any handler type.

The HandlerFunctionAdapter class

HandlerFunctionAdapter is a HandlerAdapter implementation that supports HandlerFunctions.

Given an http request, it will execute it against the provided handler and wrapt it inside a HandlerResult.

The HandlerFunction class

HandlerFunction represents a function that handles a request.

The HandlerResult class

HandlerResult Represent the result of the invocation of a handler or a handler method.

The RouterFunction class

RouterFunction represents a function that routes to a handler function. It’s route method returns a Mono describing the HandlerFunction that matches this request, or an empty if no match has been found.

Spring WebFlux Configuration

In the earlier section, we had a quick tour of some Spring WebFlux core classes, in this section we will investigate how those classes are being assembled during the Spring lifecylce.

The starting point of any Spring application is the SpringApplication#run method, parts of it is shown below.

Several application contexts type are availabe and based on the type of the application, an appropriate one will be elected. The type of the application is determined based on the presence of certain classes on the classpath, in reactive application case, a ReactiveWebServerApplicationContext would be targeted.

ReactiveWebServerApplicationContext

Once Spring has triggered the preparation of the context using the prepareContext signal, it will invoke refresh on the target application context. The refresh method will invoke at some point onRefresh signal

Next, createWebServer would be invoked.

A WebServerManager is instantiated. It will manage the web server. In a Reactive context, it would start the reactive web server.

By default the ReactiveWebServerFactory used to create the Reactive server is NettyReactiveWebServerFactory. This bean is put in the IOC container via ReactiveWebServerFactoryConfiguration, we will discuss it later.

ReactiveWebServerFactoryConfiguration

NettyReactiveWebServerFactory

ReactiveWebServerFactoryConfiguration- ReactiveWebServerFactoryAutoConfiguration

ReactiveWebServerFactoryConfiguration is an abstract class and its inner static classes would be imported in ReactiveWebServerFactoryAutoConfiguration.

WebFluxConfigurationSupport

If you look at the main class for Spring Web Flux configuration: WebFluxConfigurationSupport, it will expose a WebHandler bean of type DispatchHandler.

WebFluxConfigurationSupport is imported in WebFluxAutoConfiguration.DelegatingWebFluxConfiguration.

The HttpHandler discussed earlier is exposed in HttpHandlerAutoConfiguration as shown below.

if you look at WebHttpHandlerBuilder#applicationContext used to created the HttpHandler, our DispatchHandler would be wrapped inside a WebHttpHandlerBuilder. A look up on the Spring Application Context is performed and many filters would be added such as WebFilter (containing our security filter chain ect..,).

If we look back to WebServerManager’ startServer method, we can observe that it will invoke NettyWebServer.startHttpServer shown below.

It consists of adding the handler to the HttpServer as a child ConnectionObserver and start the binding. When a new connection is observed, a socket channel is born and handlers would be delegated all the traffic.

NettyWebServer

NettyWebServer is a WebServer that can be used to control a Reactor Netty web server. Usually this class should be created using the NettyReactiveWebServerFactory not directly.

In order to start the reactor web server start method is invoked.

As shown above, it delegates to startHttpServer.

NettyWebServer#startHttpServer consists of two main steps;

  1. wrapping the DispatcherHandler through HttpServer#handle. It consists of wrapping the handler inside an HttpServerhandle (a ConnectionObserver) and next the flow is exactly what we discussed in Visiting Reactor Netty article.

2.Then, invoke HttpServer#bindNow()

You can refer to Visiting Reactor Netty for further details.

ReactiveHttpOutputMessage

ReactiveHttpOutputMessage is a reactive HTTP output message that accepts output as a Publisher.

BodyInserter

The BodyInserter is a functional interface responsible for populating a ReactiveHttpOutputMessage with a given output message and a context used during the insertion.

As shown in the below snippet code, when invoking body(), you actually create a BodyInserter instance that we can then present as the body of the request. For example we can present a Publisher that would be drained at subscription phase and delegate data for writing (via a writer).

We will discuss it in more details later.

BaseCodecConfigurer

CodecConfigurer defines a common interface for configuring either client or server HTTP message readers and writers.

We will redirect our focus on EncoderHttpMessageWriter.

EncoderHttpMessageWriter

EncoderHttpMessageWriter is an HttpMessageWriter that wraps and delegates to an Encoder.

Pushing an event through the pipeline require invoking its HttpMessageWriter#write method briefly discussed earlier.

The higher level logic is as follows:

  • Encode the stream
  • write the data buffer to the channel via AbstractServerHttpResponse#writeWith.

As shown above AbstractServerHttpResponse#writeWith delegates to doCommit to apply basic operations such as adding headers ect.. Next, invokes writeWithInternal that would actually send the data to the socket bufffer.

Coming back to our DispatchHandler — Handling the result

The last step of the dispatch handler is to hanlde the result as discussed earlier. If we look at ServerResponseResultHandler

It will invoke AbstractServerResponse#writeTo shown below

It delegates to writeWithInternal defined in BodyInserterResponse which will invoke the body inserter discussed earlier.

writeWithMessageWriter would be called as discussed in the BodyInserter section.

Next the writer will write the message as discussed in the BaseCodecConfigure section.

You can have a look at Reactor Netty for more details about the inner workflow.

Conclusion

The goal of this article was to provide an overview of Spring WebFlux, through the configuration of the request and the response processing. I hope it was informative and useful to you.

References

https://www.baeldung.com/spring-5-webclient

https://github.com/spring-projects/spring-framework

https://medium.com/geekculture/visiting-reactor-netty-c8c0449ee0

--

--

--

A new tech publication by Start it up (https://medium.com/swlh).

Recommended from Medium

Berty, Libp2p and Bluetooth Low Energy

Kubernetes: The Container Manager

Go Development With Vim

Macro Programming in OpenOffice/LibreOffice with using Python[EN]

Apps That Are Going to Be Trending in 2021

Bundles In AssetSonar

WEMIX Communication Medium Open Notice

How to Log All SQL Queries in Laravel

How to Log All SQL Queries in Laravel

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Kondah Mouad

Kondah Mouad

Cyber Security and Software Engineer, Machine Learning Guru

More from Medium

Spring Data R2DBC - Transactions

Using the Spring Web Scopes, Part 2

Multi-module project with SpringBoot

Spring cloud config: Smaller details with bigger impacts