Spring Boot vs Spring Webflux: Performance comparison for hello world case

Mayank Choubey
Tech Tonic
Published in
4 min readMar 27

--

If you’ve been using Spring for some time or are a beginner, you must have heard about the benefits of using reactive programming rather than the traditional threadpool style architecture.

Since inception, Spring makes it easy to create Java enterprise applications. It provides everything you need to embrace the Java language in an enterprise environment, with support for Groovy and Kotlin as alternative languages on the JVM, and with the flexibility to create many kinds of architectures depending on an application’s needs.

Enter reactive programming. The original web framework included in the Spring Framework, Spring Web MVC, was purpose-built for the Servlet API and Servlet containers. The reactive-stack web framework, Spring WebFlux, was added later in version 5.0. It is fully non-blocking, supports Reactive Streams back pressure, and runs on such servers as Netty, Undertow, and Servlet containers.

Both web frameworks mirror the names of their source modules (spring-webmvc and spring-webflux) and co-exist side by side in the Spring Framework. Each module is optional. Applications can use one or the other module or, in some cases, both — for example, Spring MVC controllers with the reactive WebClient.

This article is about the potential performance benefits that comes with using reactive programming (aka Spring Boot vs Spring Webflux). I’ll use a simple hello world case to find out the extent of benefits. Basically trying to answer the question: Is it worth using Webflux (reactive programming)?

Test setup

Configuration

The test is executed on MacBook Pro M1 with 16G of RAM.

The software versions are:

  • Go 1.20.2
  • Springboot 3.0.5 over Java 17

A total of 5M (5 million) requests are executed for each type of test.

Code

The hello world code in both cases is as follows:

Spring Boot

Traditional Spring Boot requires a single Java file.

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

@GetMapping("/")
public String handleRequest() {
return "Hello World!";
}
}

Spring Webflux

Unlike traditional Spring Boot, Spring Webflux requires at least four Java files. The code is directly taken from:

HelloWorldHandler.java

package hello;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;

import reactor.core.publisher.Mono;

@Component
public class HelloWorldHandler {

public Mono<ServerResponse> hello(ServerRequest request) {
return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
.body(BodyInserters.fromValue("Hello World!"));
}
}

HelloWorldRouter.java

package hello;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;

@Configuration(proxyBeanMethods = false)
public class HelloWorldRouter {

@Bean
public RouterFunction<ServerResponse> route(HelloWorldHandler helloWorldHandler) {

return RouterFunctions
.route(GET("/"), helloWorldHandler::hello);
}
}

HelloWorldClient.java

package hello;

import reactor.core.publisher.Mono;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;

@Component
public class HelloWorldClient {

private final WebClient client;

public HelloWorldClient(WebClient.Builder builder) {
this.client = builder.baseUrl("http://localhost:3000").build();
}

public Mono<ClientResponse> getMessage() {
return this.client.get()
.uri("/")
.exchange();
}

}

Application.java

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Application {

public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
HelloWorldClient helloWorldClient = context.getBean(HelloWorldClient.class);
}
}

Execution

Each test is executed for 5M (5 million) requests.

The tests are executed for 25, 100, and 300 concurrent connections.

The load test is carried out using Bombardier HTTP testing tool.

The following are the charts showing the results, followed by a quick analysis at the end:

Analysis

It is easy to conclude that Spring Webflux (reactive programming) does bring some noticeable performance benefits over Spring Boot (threadpool). Spring Webflux offers about double the RPS with comparable resource cost.

First, because of those one-off requests taking too long, Spring Boot average numbers are not that good.

At low concurrency, the median response time of Spring Webflux is better. At high concurrency, Spring Boot is better.

Spring Webflux gets better as measurements move to 3rd quartile and 90th percentile. Even if there is a difference, it’s in the order of 1–2ms only.

Winner: Spring Webflux

--

--

Mayank Choubey
Tech Tonic

I write about Deno, Bun, and Node.js. My new book: https://choubey.gitbook.io/learn-react-in-a-day/