Spring RestTemplate - async vs sync restTemplate

I wrote the following code to test the performance of both Synt RestTemplate and AsyncRestTemplate. I just ran it several times manually on POSTMAN.

We simply pass 10 links to a GET call so that we can return 10 links:

RestTemplate is synchronous and returns at 2806ms:

ArrayList<String> references = new ArrayList<>(); ArrayList<String> links = new ArrayList<>(); RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().add(new StringHttpMessageConverter()); for (int i = 0; i < 10; i++) { ResponseEntity<String> resource = restTemplate.getForEntity(references.get(i), String.class); links.add(resource.getBody().toString()); } 

RestTemplate is asynchronous and returns at 2794ms:

 //Creating a synchronizedList so that when the async resttemplate returns, there will be no concurrency issues List<String> links = Collections.synchronizedList(new ArrayList<String>()); //CustomClientHttpRequestFactory just extends SimpleClientHttpRequestFactory but disables automatic redirects in SimpleClientHttpRequestFactory CustomClientHttpRequestFactory customClientHttpRequestFactory = new CustomClientHttpRequestFactory(); //Setting the ThreadPoolTaskExecutor for the Async calls org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor pool = new org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor(); pool.setCorePoolSize(5); pool.setMaxPoolSize(10); pool.setWaitForTasksToCompleteOnShutdown(true); pool.initialize(); //Setting the TaskExecutor to the ThreadPoolTaskExecutor customClientHttpRequestFactory.setTaskExecutor(pool); ArrayList<String> references = new ArrayList<>(); ArrayList<String> links = new ArrayList<>(); AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate(customClientHttpRequestFactory); restTemplate.getMessageConverters().add(new StringHttpMessageConverter()); for (int i = 0; i < 10; i++) { Future<ResponseEntity<String>> resource = asyncRestTemplate.getForEntity(references.get(i), String.class); ResponseEntity<String> entity = resource.get(); //this should start up 10 threads to get the links asynchronously links.add(entity.getBody().toString()); } 

In most cases, both methods actually return results with a very similar time, on average 2800 ms when calling both asynchronous and synchronous calls.

Am I doing something wrong as I would expect an asynchronous call to be much faster?

+12
source share
4 answers

I would say that you are missing out on the real benefits of AsyncRest here. You must add callbacks to each sent request so that the response is processed only if there is one.

Indeed, the getForEntity method in AsyncRestTemplate returns a ListenableFuture to which you can attach a callback task. See the ListenableFuture white paper for more information.

For example, in your case it could be:

 for (int i = 0; i < 10; i++) { ListenableFuture<ResponseEntity<String>> response = asyncRestTemplate.getForEntity(references.get(i), String.class); response.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() { @Override public void onSuccess(ResponseEntity<String> result) { // Do stuff onSuccess links.add(result.getBody().toString()); } @Override public void onFailure(Throwable ex) { log.warn("Error detected while submitting a REST request. Exception was {}", ex.getMessage()); } }); } 
+14
source

The tricky thing with Java Future is that it is not composite and is very easy to block.

In this case, calling future.get() makes your code block and waits for an answer. In fact, this approach makes sequential calls and does not use the asynchronous nature of this RestTemplate implementation.

The easiest way to fix this is to split it into two loops:

 ArrayList<Future<ResponseEntity<String>>> futures = new ArrayList<>(); for (String url : references.get()) { futures.add(asyncRestTemplate.getForEntity(url, String.class)); //start up to 10 requests in parallel, depending on your pool } for (Future<ResponseEntity<String>> future : futures) { ResponseEntity<String> entity = future.get(); // blocking on the first request links.add(entity.getBody().toString()); } 

Obviously, there are more elegant solutions, especially if you use JDK8, lambdas and ListenableFuture / CompletingFuture streams or composition libraries.

+7
source

AsyncRestTemplate methods are deprecated since Spring5. Are there other alternative examples with the latest Spring5 API for a similar program.

0
source

AsyncRestTemplate @Deprecated is currently in favor of WebClient . So no one should use this class anymore!

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/function/client/WebClient.html

0
source

All Articles