Why You Should Use Spring WebFlux Instead of the @Async Annotation
If you’re building a web application in Java, you have several options for handling asynchronous processing.
One approach is to use the @Async annotation in Spring to delegate long-running tasks to separate threads. Another approach is to use Spring WebFlux, which provides a non-blocking, event-driven programming model for building reactive web applications.
In this article, we’ll explore the benefits of using Spring WebFlux instead of the @Async annotation.
A typical application performs a variety of I/O events, such as reading and writing data to databases, external APIs and files.
Caching data, interacting with message queues, and streaming data are also common I/O events.
I have selected an external service call (GET https://ipinfo.io/161.185.160.93/geo) as a demonstration and will record the performance metrics by making an external API call using both @Async and Web-flux.
You can find code for File I/O included in the project.
- Webflux Controller
@RestController
public class ExternalAPIController {
private final WebClient webClient;
public ExternalAPIController(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.baseUrl("https://ipinfo.io").build();
}
@GetMapping(value = "/data", produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<String> getData() {
System.out.println("Hit **");
return webClient.get()
.uri("/161.185.160.93/geo")
.retrieve()
.bodyToMono(String.class);
}
}
-Async Annotation Controller
public class ExternalCall {
private final RestTemplate restTemplate;
public ExternalCall(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@GetMapping(value = "/data", produces = MediaType.APPLICATION_JSON_VALUE)
public CompletableFuture<String> getData() {
return getDataAsync();
}
@Async
public CompletableFuture<String> getDataAsync() {
String result = restTemplate.getForObject("https://ipinfo.io/161.185.160.93/geo", String.class);
return CompletableFuture.completedFuture(result);
}
}
To measure the performance of the two services, you can use a load testing tool such as Apache JMeter or Gatling to simulate a large number of requests and measure the response time and throughput of each method under various conditions.
You can also use tools like Micrometer to collect metrics on the performance of the application.
I used Apache JMeter to load and test both applications separately on two different VMs.
I generated 100 requests per second to test performance.
Here are the statistics from Jmeter:
During our stress testing, we observed that the Webflux service outperformed the @Async approach.
This was evident from the Average (4021)and Max (8090) stats for Webflux in JMeter.
When we performed silo testing using Postman, we noticed a significant reduction in response time for the Webflux service.
Webflux has several benefits over the @Async approach in Spring. It uses reactive programming and non-blocking I/O, making it highly efficient and responsive.
It’s important to keep in mind that performance optimisation requires balancing various factors, such as speed, resource usage, and ease of development and maintenance.
Therefore, it’s crucial to consider the specific requirements and constraints of your application when deciding which approach to use.
Code Link : https://github.com/AryanSahu/reactive