首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用AsyncRestTemplate多次调用接口,等待所有操作完成

使用AsyncRestTemplate多次调用接口,等待所有操作完成
EN

Stack Overflow用户
提问于 2017-06-08 10:22:38
回答 3查看 14.1K关注 0票数 9

我必须使用不同的参数多次使用RestTemplate调用Rest API。API是相同的,但它是正在改变的参数。次数也是可变的。我想使用AsyncRestTemplate,但我的主线程应该等到所有API调用都成功完成。我还想处理每个API调用返回的响应。目前我使用的是RestTemplate。它的基本形式如下所示。

代码语言:javascript
复制
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?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-06-12 16:55:17

使用AsyncRestTemplate (实际上是任何异步API )时的主要思想是在第一次发送所有请求,保留相应的未来,然后在第二次处理所有响应。你可以用两个循环简单地做到这一点:

代码语言:javascript
复制
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

票数 12
EN

Stack Overflow用户

发布于 2017-06-12 18:58:05

你可以使用Java 8 Stream API,如果可行的话:

代码语言:javascript
复制
List<String> listOfResponses = studentIdsList.stream()
    .parrallel()
    .map({studentId ->
        ResponseEntity<String> responseEntity = restTemplate.exchange(url, method, studentId, String.class);
        return responseEntity.getBody();
    })
    .collect(Collectors.toList());

这段代码将主要执行两件事:

  1. 在列表中执行请求将请求的结果保存到列表中。

更新:同意@Didier L-当你需要做很多请求时,这个解决方案可能不能正常工作。以下是更新后的版本:

代码语言:javascript
复制
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();
        }
    }
票数 5
EN

Stack Overflow用户

发布于 2017-06-13 06:23:06

这是我想建议的另一个解决方案,它使用Spring的RestTemplate而不是AsyncRestTemplate。它也在使用Java8 CompletableFuture。

代码语言:javascript
复制
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的内部来进行异步发送。显然,您可以更多地清理代码,我目前还没有太多关注这一点。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44425641

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档