[英]Call a WebService and a REST API using JDK8 Streams and CompletableFuture
I have a SOAP call that I need to make and then process the results from the SOAP call in a REST call.我有一个 SOAP 调用,我需要在 REST 调用中处理 SOAP 调用的结果。 Each set of calls is based on a batch of records.
每组调用都基于一批记录。 I am getting completely lost in trying to get this to run using JDK8 streams as asynchronous as possible.
我在试图让它尽可能异步地使用 JDK8 流运行时完全迷失了。 How can I accomplish this?
我怎样才能做到这一点?
SOAP Call: SOAP 致电:
CompletableFuture<Stream<Product>> getProducts(final Set<String> criteria)
{
return supplyAsync(() -> {
...
return service.findProducts(request);
}, EXECUTOR_THREAD_POOL);
}
REST Call: REST 致电:
final CompletableFuture<Stream<Result>> validateProducts(final Stream<Product> products)
{
return supplyAsync(() -> service
.submitProducts(products, false)
.stream(), EXECUTOR_THREAD_POOL);
}
I am trying to invoke the SOAP call, pass the result into the REST call, and collect the results using a JDK8 stream.我正在尝试调用 SOAP 调用,将结果传递给 REST 调用,并使用 JDK8 stream 收集结果。 Each SOAP->REST call is a "set" of records (or batch) similar to paging.
每个 SOAP->REST 调用都是类似于分页的记录“集”(或批处理)。 (this is totally not working right now but just an example).
(这现在完全不起作用,只是一个例子)。
@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());
}
I think there are two usage that are incorrect in your example: thenApply
and join
.我认为您的示例中有两种用法不正确:
thenApply
和join
。
To chain the 1st call (SOAP) and the 2nd call (REST), you need to use thenCompose
instead of thenApply
.要链接第一个调用 (SOAP) 和第二个调用 (REST),您需要使用
thenCompose
而不是thenApply
。 This is because method "validateProducts" returns completable futures, using "thenApply" will create CompletableFuture<CompletableFuture<Stream<Result>>>
in your stream mapping.这是因为方法“validateProducts”返回可完成的期货,使用“thenApply”将在您的 stream 映射中创建
CompletableFuture<CompletableFuture<Stream<Result>>>
。 But what you need is probably CompletableFuture<Stream<Result>>
.但是您需要的可能是
CompletableFuture<Stream<Result>>
。 Using thenCompose
can resolve this problem, because it is analogous to "Optional.flatMap" or "Stream.flatMap":使用
thenCompose
可以解决这个问题,因为它类似于“Optional.flatMap”或“Stream.flatMap”:
.mapToObj(index -> {
final Set<String> subset = subset(index, samples);
return getProducts(subset)
.thenCompose(this::validateProducts);
})
The 2nd incorrect usage is join.第二个错误用法是加入。 Using
join
blocks the current thread waiting for the result of that CompletableFuture.使用
join
阻塞当前线程等待 CompletableFuture 的结果。 In your cases, there are N completable futures, where N is the number of pages.在您的情况下,有 N 个可完成的期货,其中 N 是页数。 Instead of waiting them one by one, the better solution is to wait all the them use
CompletableFuture.allOf(...)
.与其一一等待,更好的解决方案是等待所有它们使用
CompletableFuture.allOf(...)
。 This method returns a new CompletableFuture that is completed when all of the given CompletableFutures complete.此方法返回一个新的 CompletableFuture,它在所有给定的 CompletableFuture 完成时完成。 So I suggest that you modify your stream usage and return a list of futures.
所以我建议你修改你的 stream 用法并返回一个期货列表。 Then, wait the completion.
然后,等待完成。 And finally, retrieve the results:
最后,检索结果:
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
}
You can see the complete program on GitHub .您可以在GitHub上看到完整的程序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.