Calling Mutiple Webservice At Same Time in Spring Java

Calling mutiple webservice at same time in Spring Java

One option you could consider is the Java8 streams like:

public void check() {
List<String> endPoints = Arrays.asList("http://www.google.com", "http://www.stackoverflow.com", "inexistent");
{
// this will execute the requests in parallel
List<Boolean> collected = performCheckOverStream(endPoints.parallelStream());
System.out.println(collected);
}
{
// this will execute the requests in serial
List<Boolean> collected = performCheckOverStream(endPoints.stream());
System.out.println(collected);
}

}

private List<Boolean> performCheckOverStream(Stream<String> stream) {
List<Boolean> collected = stream.map(new Function<String, Boolean>() {
@Override
public Boolean apply(String t) {
// do what you need here
}
}).collect(Collectors.toList());
return collected;
}

Using Spring you could either use a @Async annotated method or even use the AsyncRestTemplate, in both cases you will receive a Future<?>. A nice introduction to @Async can be found here and to the AsyncRestTemplate here.

Calling multiples webservices at same time using Java

You can use ExecutorService to submit Callable and call Future.get() to retrieve result as shown below (change Future<String> to the appropriate return value). You should also think about error handling and creating threadpool outside of method (if possible at app startup).

public Dossie procuraPorCPF(String cpf) {

ExecutorService executor = Executors.newFixedThreadPool(3);

Future<String> cnh = executor.submit(() -> detectaClientCnh.verificaCNH(cpf));
Future<String> fotoCnh = executor.submit(() -> detectaClientCnhFoto.verificaFotoCNHPorCpf(cpf));
Future<String> pm =
executor.submit(() -> consultaPMWService.getPMPorCPF(cpf).getProcuraPMPorCPFResult());

Dossie dossie = new Dossie();

try {
dossie.setCnh(cnh.get());
dossie.setFotoCnh(fotoCnh.get());
dossie.setPm(pm.get());
} catch (InterruptedException | ExecutionException cause) {
cause.printStackTrace();
}
executor.shutdown();
return dossie;
}

Best way to make multiple asynchronous calls to same web service

This is just an improvement over @shawn answer. With the implementation provided earlier, sometimes I was facing issue due to below block:

while (responses < futures.size()) {        
for (Future<ResponseEntity<List<Record>>> future : futures) {
if (future.isDone()) {
responses++;
try {
ResponseEntity<List<Record>> responseEntity = future.get();
fullListOfRecords.addAll(responseEntity.getBody());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}

Here if 6 threads are processed, sometimes same thread is allowed to enter multiple times in above block so it ends up having duplicate records in response. So to avoid such situation, I have added callback block to create final response which make sure no duplicate response, though we still need while(responses < futures.size()) loop block with future.get() to block method to return final combined response until all the asynchronous calls are processed.

@Component
public class SampleAsyncService {
private RestTemplate restTemplate;
private AsyncRestTemplate asyncRestTemplate;

@Value("${myapp.batchSize:1000}")
private int batchSize;

public SampleAsyncService(AsyncRestTemplate asyncRestTemplate, RestTemplate restTemplate) {
this.asyncRestTemplate = asyncRestTemplate;
this.restTemplate = restTemplate;
}

public List<Record> callForRecords() {
ResponseEntity<Integer> response = restTemplate.getForEntity("http://localhost:8081/countService",
Integer.class);
int totalRecords = response.getBody().intValue();
List<Future<ResponseEntity<List<Record>>>> futures = new ArrayList<Future<ResponseEntity<List<Record>>>>();
for (int offset = 0; offset < totalRecords;) {
ListenableFuture<ResponseEntity<List<Record>>> future = asyncRestTemplate.exchange(
"http://localhost:8081/records?startRow={}&endRow={}", HttpMethod.GET, null,
new ParameterizedTypeReference<List<Record>>() {
}, offset, batchSize);
future.addCallback(
new ListenableFutureCallback<ResponseEntity<ChatTranscript>>() {
@Override
public void onSuccess(ResponseEntity<ChatTranscript> response) {
fullListOfRecords.addAll(responseEntity.getBody());
log.debug("Success: " + Thread.currentThread());
}

@Override
public void onFailure(Throwable t) {
log.debug("Error: " + Thread.currentThread());
}
}
);
futures.add(future);
offset = offset + batchSize;
}

int responses = 0;
List<Record> fullListOfRecords = new ArrayList<Record>();
while (responses < futures.size()) {
for (Future<ResponseEntity<List<Record>>> future : futures) {
if (future.isDone()) {
responses++;
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}

return fullListOfRecords;
}

public class Record {
}

}

Multiple REST Calls using Spring Boot

You can simply use WebClient, as it's non-blocking by design.

see e.g.: https://newbedev.com/springboot-how-to-use-webclient-instead-of-resttemplate-for-performing-non-blocking-and-asynchronous-calls
But there are lots of other resources on the web.

However... if you're using RestTemplate:

@Service
public class AsyncService {

private final RestTemplate restTemplate;

public AsyncService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

@Async
public CompletableFuture<ResponseDto[]> callAsync(RequestDto requestDto) {
ResponseDto[] responseDtos = restTemplate.postForObject("someUrl", requestDto, ResponseDto[].class);

return CompletableFuture.completedFuture(responseDtos);
}
}

Then you can simply loop though all requests from whatever place is ideal for your context using standard Java Future mechanisms.

Just make sure to add @EnableAsync to your application

A more detailed tutorial can be found here: https://spring.io/guides/gs/async-method/

Do multiple calls to different methods in parallel in spring

Daniel's answer is right but I would like to add something more to it. If you want to do something with your results but don't want to block with Future#get then I would suggest you to use CompletableFuture class.

It will let you add various actions which will be triggered on its completion.
There is also a really nice article on how to use CompletableFuture with Spring's @async annotation. Here it the link. Completable futures with Spring async

Can Spring Boot application handle multiple requests simultaneously?

Yes, Spring boot can handle simultaneously requests!
If your servlet container is tomcat under the hood, it can handle 200 simultaneous requests.

Below snippet highlights the point, but refer original spring boot source

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
public static class Tomcat {
public static class Threads {
private int max = 200; // Maximum amount of worker threads
}
}
}

However, you can override this value by adding server.tomcat.threads.max to your application.properties or application.yml.

Spring will manage a pool of connections and handle the distribution of entity managers (according to the minimum and maximum of connections you specify in your properties).
I believe you can read more about it here: When are connections returned to the connection pool with Spring JPA (Hibernate) Entity Manager?



Related Topics



Leave a reply



Submit