Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring RestTemplate - async vs sync restTemplate

Tags:

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

We are just passing 10 references into a GET call so that we can return 10 links:

RestTemplate - synchronous and returns in 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 - asynchronous and returns in 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 back the results with a very similar time, averaging 2800ms in both async and sync calls.

Am I doing something incorrect as I would have expected the async call to be much faster?

like image 349
Simon Avatar asked Jul 22 '15 19:07

Simon


People also ask

Is RestTemplate synchronous or asynchronous?

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.

Why RestTemplate is deprecated?

RestTemplate provides a synchronous way of consuming Rest services, which means it will block the thread until it receives a response. RestTemplate is deprecated since Spring 5 which means it's not really that future proof.

What is the alternative for RestTemplate in Spring boot?

WebClient offers a modern alternative to the RestTemplate with efficient support for both sync and async, as well as streaming scenarios. The RestTemplate will be deprecated in a future version and will not have major new features added going forward. We are writing a new project using spring boot 2.0.


2 Answers

Nowadays, AsyncRestTemplate is @Deprecated in favor of WebClient. So nobody should use that class anymore!

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

like image 176
membersound Avatar answered Sep 18 '22 22:09

membersound


I would say that you're missing the real benefits of the AsyncRest here. You should add callbacks to each requests you're sending so that the response will be processes only when available.

Indeed, the getForEntity method of an AsyncRestTemplate returns a ListenableFuture to which you can connect a callback task. See the official doc ListenableFuture for further 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());
            }
        });
}
like image 23
Ugo Giordano Avatar answered Sep 17 '22 22:09

Ugo Giordano