[英]Call a WebService and a REST API using JDK8 Streams and CompletableFuture
我有一個 SOAP 調用,我需要在 REST 調用中處理 SOAP 調用的結果。 每組調用都基於一批記錄。 我在試圖讓它盡可能異步地使用 JDK8 流運行時完全迷失了。 我怎樣才能做到這一點?
SOAP 致電:
CompletableFuture<Stream<Product>> getProducts(final Set<String> criteria)
{
return supplyAsync(() -> {
...
return service.findProducts(request);
}, EXECUTOR_THREAD_POOL);
}
REST 致電:
final CompletableFuture<Stream<Result>> validateProducts(final Stream<Product> products)
{
return supplyAsync(() -> service
.submitProducts(products, false)
.stream(), EXECUTOR_THREAD_POOL);
}
我正在嘗試調用 SOAP 調用,將結果傳遞給 REST 調用,並使用 JDK8 stream 收集結果。 每個 SOAP->REST 調用都是類似於分頁的記錄“集”(或批處理)。 (這現在完全不起作用,只是一個例子)。
@Test
public void should_execute_validations()
{
final Set<String> samples = generateSamples();
//Prepare paging...
final int total = samples.size();
final int pages = getPages(total);
log.debug("Items: {} / Pages: {}", total, pages);
final Stopwatch stopwatch = createStarted();
final Set<Result> results = range(0, pages)
.mapToObj(index -> {
final Set<String> subset = subset(index, samples);
return getProducts(subset)
.thenApply(this::validateProducts);
})
.flatMap(CompletableFuture::join)
.collect(toSet());
log.debug("Executed {} calls in {}", pages, stopwatch.stop());
assertThat(results, notNullValue());
}
我認為您的示例中有兩種用法不正確: thenApply
和join
。
要鏈接第一個調用 (SOAP) 和第二個調用 (REST),您需要使用thenCompose
而不是thenApply
。 這是因為方法“validateProducts”返回可完成的期貨,使用“thenApply”將在您的 stream 映射中創建CompletableFuture<CompletableFuture<Stream<Result>>>
。 但是您需要的可能是CompletableFuture<Stream<Result>>
。 使用thenCompose
可以解決這個問題,因為它類似於“Optional.flatMap”或“Stream.flatMap”:
.mapToObj(index -> {
final Set<String> subset = subset(index, samples);
return getProducts(subset)
.thenCompose(this::validateProducts);
})
第二個錯誤用法是加入。 使用join
阻塞當前線程等待 CompletableFuture 的結果。 在您的情況下,有 N 個可完成的期貨,其中 N 是頁數。 與其一一等待,更好的解決方案是等待所有它們使用CompletableFuture.allOf(...)
。 此方法返回一個新的 CompletableFuture,它在所有給定的 CompletableFuture 完成時完成。 所以我建議你修改你的 stream 用法並返回一個期貨列表。 然后,等待完成。 最后,檢索結果:
List<CompletableFuture<Stream<Result>>> futures = range(0, pages)
.mapToObj(index -> {
final Set<String> subset = subset(index, samples);
return getProducts(subset).thenCompose(this::validateProducts);
})
.collect(Collectors.toList());
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
for (CompletableFuture<Stream<Result>> cf : futures) {
// TODO Handle the results and exceptions here
}
您可以在GitHub上看到完整的程序。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.