简体   繁体   English

使用 JDK8 Streams 和 CompletableFuture 调用 WebService 和 REST API

[英]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 .我认为您的示例中有两种用法不正确: thenApplyjoin

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM