使用Resttemplate的多个异步HTTP请求

时间:2019-02-11 21:37:44

标签: java java-8 resttemplate spring-web

我有一个使用spring RestTemplate调用多个URL的服务。

为了提高性能,我想并行执行这些请求。我可以使用的两种选择是:

  • 利用fork-join公共池的java 8并行流
  • 使用隔离的线程池实现美好的未来

只是想知道在阻塞I / O调用中使用并行流是否是最佳实践?

2 个答案:

答案 0 :(得分:2)

可完成的将来将是实现此目的的更好方法,因为它在语义上与任务更相关,并且您可以在任务进行时保持代码流继续进行。

如果使用流,除了内部具有异常处理的lambda的笨拙以及它与任务无关之外,就语义而言,如在管道中一样,您将不得不等待所有流完成,即使它们是并行发生的。为避免这种情况,您将需要期货,但随后您将回到第一个解决方案。

您可能会考虑使用流创建期货的混合。但是考虑到这是一组阻塞的IO请求,您可能没有足够的请求或时间来利用并行流,该库可能不会为您并行拆分任务,并且通过循环会更好

答案 1 :(得分:2)

ForkJoinPool对于执行IO工作而言并不理想,因为您无法从其工作窃取属性中获得任何好处。如果您打算使用commonPool,而应用程序的其他部分也是如此,则可能会干扰它们。专用的线程池,例如ExecutorService,可能是这两者之间更好的解决方案。

我想提出一些更好的建议。与其亲自编写所有异步包装代码,不如考虑使用Spring的AsyncRestTemplate。它包含在Spring Web库中,其API与RestTemplate几乎相同。

  

Spring的中心类,用于异步客户端HTTP访问。   公开与RestTemplate类似的方法,但返回ListenableFuture   包装器,而不是具体的结果。

     

[...]

     

注意:默认情况下,AsyncRestTemplate依赖于标准JDK工具   建立HTTP连接。您可以切换为使用其他HTTP   库,例如Apache HttpComponents,Netty和OkHttp   构造函数接受AsyncClientHttpRequestFactory

ListenableFuture实例可以通过ListenableFuture::completable()轻松转换为CompletableFuture实例。

如Javadoc中所述,您可以通过指定AsyncClientHttpRequestFactory来控制要使用的异步机制。对于列出的每个库,都有许多内置的实现。在内部,其中一些库可能会执行您建议的操作,并在专用线程池上运行阻塞IO。其他,例如Netty(如果有内存),使用非阻塞IO运行连接。您可能会从中受益。

然后由您自己决定如何减少结果。使用CompletableFuture,您可以访问anyOfallOf助手以及任何组合实例方法。

例如,

URI exampleURI = URI.create("https://www.stackoverflow.com");

AsyncRestTemplate template = new AsyncRestTemplate/* specific request factory*/();
var future1 = template.exchange(exampleURI, HttpMethod.GET, null, String.class).completable();
var future2 = template.exchange(exampleURI, HttpMethod.GET, null, String.class).completable();
var future3 = template.exchange(exampleURI, HttpMethod.GET, null, String.class).completable();

CompletableFuture.allOf(future1, future2, future3).thenRun(() -> {
    // you're done
});

此后,不推荐使用

AsyncRestTemplate,而推荐使用Spring Web Flux'WebClient。这个API有很大的不同,因此我不再赘述(除了说它确实可以让您找回CompletableFuture之外。)