I'm looking for a clarification on the bolded text in the statement below (I've provided the full paragraph for context only):
The RestTemplate is not a good fit for use in non-blocking applications, and therefore Spring WebFlux application should always use the WebClient. The WebClient should also be preferred in Spring MVC, in most high concurrency scenarios, and for composing a sequence of remote, inter-dependent calls.
Found here: https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html
In particular what is the benefit of using WebClient
over RestTemplate
for Spring MVC apps? How would WebClient
achieve higher scale vs say RestTemplate
configured with apache HttpClient
and PoolingHttpClientConnectionManager
with suitably configured connection and socket configuration?
After a bit of research, I believe the answer lies in Spring's DeferredResult. To steal a bit of verbiage from this blog,
DeferredResult is a container for possibly not-yet-finished computation that will be available in future. Spring MVC uses it to represent asynchronous computation and take advantage of Servlet 3.0 AsyncContext asynchronous request handling.
I believe what happened was prior to WebFlux, this DeferredResult concept was a first cut at supporting asynchronous IO inside of Spring MVC, for example there is also a now deprecated AsyncRestTemplate which returns ListenableFuture
wrappers.
So this means that if I have a relatively simple REST API with spring MVC, I could potentially return a DeferredFuture
that generates its result asynchronously via WebClient
, and thus gain some of the benefits of asynchronous processing without having to migrate away from Spring MVC (which may be infeasible for some projects).
WebClient
is non-blocking, while RestTemplate
is blocking/synchronous. If you're using the non-blocking WebFlux API with a blocking library, you're essentially turning it into a blocking API.
Think of RestTemplate
as actually creating a new Thread for each event, vs WebClient
creating a Task (as if on a queue, which is essentially what Reactor manages for you behind the covers).
You'll soon reach Thread starvation if for every non-blocking task you have a blocking call backing it (as would be the case for each RestTemplate
; note that delegating to the ConnectionManager
is still making blocking call).
On the other hand a Task will get queued up by the reactive framework and get executed when you have the appropriate resources available.
Why use WebClient with Spring MVC
WebClient is non-blocking! You can use all of the Flux
features with it (pub-sub, backpressure, etc.). This helps conserve resources (i.e. you use less threads and less memory), and Reactor will allow you to maximize the use of threads you're not using.
The question here isn't really "why should I use WebClient" with Spring MVC, the question is, "why should I use a reactive/non-blocking" framework with my application. Lots of examples (here's one) on the internet of this question and it's answers.
Mono
and Flux
can also return a Java 8 CompletableFuture
if you want to use a non-reactive non-blocking construct.
Why use WebClient with WebFlux
See this quote from the page you referenced in that documentation:
WebClient uses the same codecs as WebFlux server applications do, and shares a common base package, some common APIs, and infrastructure with the server functional web framework. The API exposes Reactor Flux and Mono types
The key point there is that WebClient
uses the same reactive non-blocking types as does Flux
. That's why the integrate so nicely and you get the nice tasking feature. For example (and I'm borrowing a chunk of code from that doc):
WebClient client = WebClient.create("http://example.org");
Mono<Void> result = client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.body(personMono, Person.class)
.retrieve()
.bodyToMono(Void.class);
See how that piece of code yields a Mono
? That's a reactive construct the WebFlux
is built on and that's why you'd use it with the framework. For example, you can actually return that Mono
reactively in a Controller
call:
@PostMapping("/person")
Mono<Void> create(@RequestBody Publisher<Person> personStream) {
// ... above code could go here...
return result;
}
This type of thing is the key reason why they say you should use WebClient
with the WebFlux
library.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With