Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RestTemplate vs WebClient benefits in Servlet based web-mvc app

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?

like image 588
Kevin Avatar asked Aug 21 '18 17:08

Kevin


2 Answers

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).

like image 192
Kevin Avatar answered Oct 20 '22 14:10

Kevin


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.

like image 23
Dovmo Avatar answered Oct 20 '22 13:10

Dovmo