我必须使用不同的参数多次使用RestTemplate调用Rest API。API是相同的,但它是正在改变的参数。次数也是可变的。我想使用AsyncRestTemplate,但我的主线程应该等到所有API调用都成功完成。我还想处理每个API调用返回的响应。目前我使用的是RestTemplate。它的基本形式如下所示。
List<String> listOfResponses = new ArrayList<String>();
for (Integer studentId : studentIdsList) {
String respBody;
try {
ResponseEntity<String> responseEntity = restTemplate.exchange(url, method, requestEntity, String.class);
} catch (Exception ex) {
throw new ApplicationException("Exception while making Rest call.", ex);
}
respBody = requestEntity.getBody();
listOfResponses.add(respBody);
}在这种情况下,如何实现AsyncRestTemplate?
发布于 2017-06-12 16:55:17
使用AsyncRestTemplate (实际上是任何异步API )时的主要思想是在第一次发送所有请求,保留相应的未来,然后在第二次处理所有响应。你可以用两个循环简单地做到这一点:
List<ListenableFuture<ResponseEntity<String>>> responseFutures = new ArrayList<>();
for (Integer studentId : studentIdsList) {
// FIXME studentId is not used
ListenableFuture<ResponseEntity<String>> responseEntityFuture = restTemplate.exchange(url, method, requestEntity, String.class);
responseFutures.add(responseEntityFuture);
}
// now all requests were send, so we can process the responses
List<String> listOfResponses = new ArrayList<>();
for (ListenableFuture<ResponseEntity<String>> future: responseFutures) {
try {
String respBody = future.get().getBody();
listOfResponses.add(respBody);
} catch (Exception ex) {
throw new ApplicationException("Exception while making Rest call.", ex);
}
}注意:如果您需要将响应与原始请求配对,则可以将未来列表替换为映射或request+response对象列表。
我还注意到你的问题中没有使用studentId。
发布于 2017-06-12 18:58:05
你可以使用Java 8 Stream API,如果可行的话:
List<String> listOfResponses = studentIdsList.stream()
.parrallel()
.map({studentId ->
ResponseEntity<String> responseEntity = restTemplate.exchange(url, method, studentId, String.class);
return responseEntity.getBody();
})
.collect(Collectors.toList());这段代码将主要执行两件事:
更新:同意@Didier L-当你需要做很多请求时,这个解决方案可能不能正常工作。以下是更新后的版本:
List<String> listOfResponses = studentIdsList.stream()
.map(studentId -> asyncRestTemplate.exchange(url, method, studentId, String.class)
.collect(Collectors.toList()).stream()
.map(this::retrieveResult)
.collect(Collectors.toList());
/**
* Retrieves results of each request by blocking the main thread. Note that the actual request was performed on the previous step when
* calling asyncRestTemplate.exchange(url, method, studentId, String.class)
*/
private String retrieveResult(ListenableFuture<ResponseEntity<String>> listenableFuture) {
try {
return listenableFuture.get().getBody();
} catch (Exception e) {
e.printStackTrace();
}
}发布于 2017-06-13 06:23:06
这是我想建议的另一个解决方案,它使用Spring的RestTemplate而不是AsyncRestTemplate。它也在使用Java8 CompletableFuture。
public void sendRequestsAsync(List<Integer> studentList) {
List<CompletableFuture<Void>> completableFutures = new ArrayList<>(studentList.size()); //List to hold all the completable futures
List<String> responses = new ArrayList<>(); //List for responses
ExecutorService yourOwnExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
for (Integer studentId : studentList) { //Iterate student list
CompletableFuture<Void> requestCompletableFuture = CompletableFuture
.supplyAsync(
() -> restTemplate.exchange("URL/" + studentId, HttpMethod.GET, null, String.class),
yourOwnExecutor
)//Supply the task you wanna run, in your case http request
.thenApply((responseEntity) -> {
responses.add(responseEntity.getBody());
return responseEntity;
})//now you can add response body to responses
.thenAccept((responseEntity) -> {
doSomeFinalStuffWithResponse(responseEntity);
})//here you can do more stuff with responseEntity (if you need to)
.exceptionally(ex -> {
System.out.println(ex);
return null;
});//do something here if an exception occurs in the execution;
completableFutures.add(requestCompletableFuture);
}
try {
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[completableFutures.size()])).get(); //Now block till all of them are executed by building another completablefuture with others.
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}我更喜欢这个解决方案,因为我可以链接任何我想要的业务逻辑,而不需要依赖Spring的内部来进行异步发送。显然,您可以更多地清理代码,我目前还没有太多关注这一点。
https://stackoverflow.com/questions/44425641
复制相似问题