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
Determine the Number of Pages in a Pdf File
Read Huge Excel File(500K Rows) in Java
Kafka: Failed to Update Metadata After 60000 Ms
How to Clean Project Cache in Intellij Idea Like Eclipse'S Clean
Batch Inserts Using JPA Entitymanager
Spring Boot Required Request Part 'File' Is Not Present
How to Set the Radio Button Based on the Value Fetched from the Database
How to Delete the Content of Text File Without Deleting Itself
How to Force Java Server to Accept Only Tls 1.2 and Reject Tls 1.0 and Tls 1.1 Connections
Check Username and Password in Java Database and Give Wrong Password Message If False
Recyclerview Not Calling Oncreateviewholder or Onbindview
How to Find the Number of Times If or Else Code Has Executed
Select the Letters After - in a String
Using Nested While Loop to Print Pyramid of Stars
Autowiring Httpservletrequest in Spring Controller
How to Create Comma Separated String in Single Quotes from Arraylist of String in Java