首页 > 解决方案 > CompletableFuture - 运行多个 rest 调用抛出 java.util.concurrent.CompletionException

问题描述

我有一个服务对另一个服务进行 2 次调用,然后组合响应并生成响应。

public HashMap<String,Double> getResp(String requestJson, double defaultScore, String anomalySelfInclUrl,String anomalySelfExclUrl){
        CompletableFuture<Double> f1 = getHelper(requestJson,anomalySelfInclUrl);
        CompletableFuture <Double>f2=  getHelper(requestJson,anomalySelfExclUrl);
        AnomalyResponse anomalyResponse =new AnomalyResponse();
        HashMap<String,Double> respMap= new HashMap<>();
        CompletableFuture.allOf(f1,f2)
                .thenRun(() -> {
                    try {
                        Double anomalySelfModelRes = f1.get();
                        Double anomalyExclModelRes = f2.get();
                        respMap.put(Constants.selfInc,anomalySelfModelRes);
                        respMap.put(Constants.selfExcl,anomalyExclModelRes);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }).join();
        return respMap;
    }

public CompletableFuture<Double> getHelper(String requestJson, String url)  {
        return CompletableFuture.supplyAsync(() -> {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<String> entity = new HttpEntity<>(requestJson, headers);
            String resp =restTemplate.postForObject(url, entity, String.class);
            JsonObject json = new JsonParser().parse(resp).getAsJsonObject();
            return json.get("score").getAsDouble();
        });

    }

在 getResp 方法中,我使用可完成的未来来创建 2 个 post 调用(通过 getHelper 方法)。一旦两个 post 调用都完成,我会将它们添加到 HashMap 并返回它。但是我在postForObject()方法中收到以下错误。

org.jboss.resteasy.spi.UnhandledException: java.util.concurrent.CompletionException

该错误似乎正在发生,因为被调用的服务没有接收到发布的 json 数据和标头(包装在 HttpEntity 中)。这怎么会发生?在顺序调用期间不会出现此问题。

标签: javaspring-bootcompletable-future

解决方案


如果在可完成的将来执行该方法时出现异常,则抛出完成异常。

因此,假设您从 API 中获得 401,并且您restTemplate将抛出未经授权的异常。它将被包装在 CompletionException 中。

您可以从objOfCompletionException.getCause()方法调用中获得实际响应。它将包含实际发生异常的所有详细信息。


推荐阅读