The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:
Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.
Get started with mocking and improve your application tests using our Mockito guide:
Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.
Get started with understanding multi-threaded applications with our Java Concurrency guide:
Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:
Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.
But these can also be overused and fall into some common pitfalls.
To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:
Get started with Spring and Spring Boot, through the Learn Spring course:
>> LEARN SPRINGExplore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:
Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.
I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.
You can explore the course here:
Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.
Get started with Spring Data JPA through the guided reference course:
Refactor Java code safely β and automatically β with OpenRewrite.
Refactoring big codebases by hand is slow, risky, and easy to put off. Thatβs where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.
Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions β one for newcomers and one for experienced users. Youβll see how recipes work, how to apply them across projects, and how to modernize code with confidence.
Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.
1. Overview
In this tutorial, weβre going to compare two of Springβs web client implementations β RestTemplate and new Spring 5βs reactive alternative WebClient.
2. Blocking vs Non-Blocking Client
Itβs a common requirement in web applications to make HTTP calls to other services. So, we need a web client tool.
2.1. RestTemplate Blocking Client
For a long time, Spring has been offering RestTemplate as a web client abstraction. Under the hood, RestTemplate uses the Java Servlet API, which is based on the thread-per-request model.
This means that the thread will block until the web client receives the response. The problem with the blocking code is due to each thread consuming some amount of memory and CPU cycles.
Letβs consider having a lot of incoming requests, which are waiting for some slow service needed to produce the result.
Sooner or later, the requests waiting for the results will pile up. Consequently, the application will create many threads, which will exhaust the thread pool or occupy all the available memory. We can also experience performance degradation because of the frequent CPU context (thread) switching.
2.2. WebClient Non-Blocking Client
On the other side, WebClient uses an asynchronous, non-blocking solution provided by the Spring Reactive framework.
While RestTemplate uses the caller thread for each event (HTTP call), WebClient will create something like a βtaskβ for each event. Behind the scenes, the Reactive framework will queue those βtasksβ and execute them only when the appropriate response is available.
The Reactive framework uses an event-driven architecture. It provides means to compose asynchronous logic through the Reactive Streams API. As a result, the reactive approach can process more logic while using fewer threads and system resources, compared to the synchronous/blocking method.
WebClient is part of the Spring WebFlux library. So, we can also write client code using a functional, fluent API with reactive types (Mono and Flux) as a declarative composition.
3. Comparison Example
To demonstrate the differences between these two approaches, weβd need to run performance tests with many concurrent client requests.
We would see a significant performance degradation with the blocking method after a certain number of parallel client requests.
However, the reactive/non-blocking method should give constant performances, regardless of the number of requests.
For this article, weβll implement two REST endpoints, one using RestTemplate and the other using WebClient. Their task is to call another slow REST web service, which returns a list of tweets.
To start, weβll need the Spring Boot WebFlux starter dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
And hereβs our slow service REST endpoint:
@GetMapping("/slow-service-tweets")
private List<Tweet> getAllTweets() {
Thread.sleep(2000L); // delay
return Arrays.asList(
new Tweet("RestTemplate rules", "@user1"),
new Tweet("WebClient is better", "@user2"),
new Tweet("OK, both are useful", "@user1"));
}
3.1. Using RestTemplate to Call a Slow Service
Letβs now implement another REST endpoint that will call our slow service via the web client.
First, weβll use RestTemplate:
@GetMapping("/tweets-blocking")
public List<Tweet> getTweetsBlocking() {
log.info("Starting BLOCKING Controller!");
final String uri = getSlowServiceUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<List<Tweet>> response = restTemplate.exchange(
uri, HttpMethod.GET, null,
new ParameterizedTypeReference<List<Tweet>>(){});
List<Tweet> result = response.getBody();
result.forEach(tweet -> log.info(tweet.toString()));
log.info("Exiting BLOCKING Controller!");
return result;
}
When we call this endpoint, due to the synchronous nature of RestTemplate, the code will block waiting for the response from our slow service. The rest of the code in this method will be run only when the response has been received.
Hereβs what weβll see in the logs:
Starting BLOCKING Controller!
Tweet(text=RestTemplate rules, username=@user1)
Tweet(text=WebClient is better, username=@user2)
Tweet(text=OK, both are useful, username=@user1)
Exiting BLOCKING Controller!
3.2. Using WebClient to Call a Slow Service
Second, letβs use WebClient to call the slow service:
@GetMapping(value = "/tweets-non-blocking",
produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Tweet> getTweetsNonBlocking() {
log.info("Starting NON-BLOCKING Controller!");
Flux<Tweet> tweetFlux = WebClient.create()
.get()
.uri(getSlowServiceUri())
.retrieve()
.bodyToFlux(Tweet.class);
tweetFlux.subscribe(tweet -> log.info(tweet.toString()));
log.info("Exiting NON-BLOCKING Controller!");
return tweetFlux;
}
In this case, WebClient returns a Flux publisher, and the method execution gets completed. Once the result is available, the publisher will start emitting tweets to its subscribers.
Note that a client (in this case, a web browser) calling this /tweets-non-blocking endpoint will also be subscribed to the returned Flux object.
Letβs observe the log this time:
Starting NON-BLOCKING Controller!
Exiting NON-BLOCKING Controller!
Tweet(text=RestTemplate rules, username=@user1)
Tweet(text=WebClient is better, username=@user2)
Tweet(text=OK, both are useful, username=@user1)
Note that this endpoint method completed before the response was received.
4. Conclusion
In this article, we explored two different ways of using web clients in Spring.
RestTemplate uses Java Servlet API and is therefore synchronous and blocking.
Conversely, WebClient is asynchronous and will not block the executing thread while waiting for the response to come back. The notification will be produced only when the response is ready.
RestTemplate will still be used. But in some cases, the non-blocking approach uses much fewer system resources compared to the blocking one. So, WebClient is a preferable choice in those cases.
