Spring MVC or Spring WebFlux?

Squeeds Julkalender | 2022-12-04 | Oscar Hansson
If you have worked with Java and Spring you may have come across Spring MVC and Spring WebFlux, two web frameworks used for creating Restful apis in Spring. Each request to Spring MVC uses a single thread, which can be blocking, whereas Spring Webflux does not block a thread during execution. In this short post I will compare the features of these two and give some insight into what to choose for your architecture needs.
spring-mvc-and-webflux-venn.png

Spring MVC

Spring MVC uses a servlet API to handle coordination of incoming http requests to the correct handlers, which is often based around @Controller-annotations with annotation-mappings for post,get,put and delete operations. In this context each request is assigned to a new thread where it is processed. In Spring MVC each thread is blocking so if a request is made to an external service within a thread then that thread will wait for the response until it continues to execute the rest of the code. Below, the request handling is illustrated, where the servlet handles the incoming call and redirects it to the WebApplicationContext where our controllers reside. The WebApplicationContext then communicates with our service layer.

High-level illustration of request-handling in Spring MVC

Spring WebFlux

Spring WebFlux uses a Webhandler API which is similar to the Servlet API but wth non-blocking handlers. There are a lot of similarities in code style between Spring MVC and Spring WebFlux and if you are used to working with annotated controllers then you can continue to use them with WebFlux. As mentioned earlier, WebFlux is non-blocking and asynchronous which means that when a WebFlux application makes an external blocking call the thread will not wait but instead will be released so that it can be used to process other requests. When a response is returned from the external service a new thread gets assigned and will process the response. By making the application non-blocking this eliminates the threads that hog memory and just waits for a response from some other service or process.

Comparison

One of the pros of choosing Spring MVC is that it uses imperative programming, where code is processed in a sequence of statements that may change the state of the application. This is easier to write, understand and debug for developers which is good since it minimizes the time spent on understanding the programming flow of an application. Furthermore, If you are using Java Database Connectivity (JDBC) to connect to your database then it is oftentimes better to go with a Spring MVC implementation since JDBC is a blocking API and requires the use of the same thread when querying and recieving the response, so the thread cannot be released while waiting for a response. To make the most out of Spring WebFlux the application needs to be non-blocking in its entirety and by relying on JDBC this is not the case. For a fully non-blocking stack one can use Spring Data R2DBC which is a non-blocking reactive relational database connection API that can be used with Spring WebFlux. At the moment stuff like caching, lazy-loading and other features are not offered which makes this quite limited in its current state. For those that uses a microservice architecture one way to migrate to Spring WebFlux could be to move the database layer to its own microservice that runs Spring MVC and in the original application move to WebFlux and make calls to the new blocking microservice. It is completely fine to have a mix of Spring MVC and Spring WebFlux services working together for example in a microservice environment. If we have an endpoint /objects/{id} where we can get an object based on some id then the code for the WebFlux controller endpoint could look like this:

which makes a call to some apiService which is the internal Spring MVC-based service that will fetch the object from the database using JDBC. The Spring MVC application controller will look like this:

As you can see, the coding style is not that different if you are used to Java Streams and Optionals. The main difference is the wrapping of the response in a "Mono" in the WebFlux case. In short, a Mono is a Publisher that will publish either zero or one value some time in the future, thus making the operations on these asynchronous. A Mono can roughly be compared to a Future in Java.

The Spring team makes a point that the key benefit of using a reactive stack i.e WebFlux is the ability to scale with a small fixed number of threads and less memory since the memory utilization is better. Ultimately the decision to use either Spring MVC or Spring WebFlux depends on the goal of the project. For most use cases Spring MVC will work fine but if you know that predictable scalability during high loads is important then Spring WebFlux could be worth checking out. You can dive deeper into this topic by reading the Spring documentation.