我可以使用从Spring5的WebClient返回的Flux的block()方法吗?

时间:2018-01-30 09:17:49

标签: spring-boot spring-webflux

我创建了Spring Boot 2.0演示应用程序,其中包含两个使用WebClient进行通信的应用程序。当我从WebClient的响应中使用Flux的block()方法时,他经常会停止沟通。我想出于某种原因使用List not Flux。

服务器端应用程序是这样的。它只返回Flux对象。

@GetMapping
public Flux<Item> findAll() {
    return Flux.fromIterable(items);
}

客户端(或BFF端)应用程序是这样的。我从服务器获取Flux并通过调用block()方法将其转换为List。

@GetMapping
public List<Item> findBlock() {
    return webClient.get()
        .retrieve()
        .bodyToFlux(Item.class)
        .collectList()
        .block(Duration.ofSeconds(10L));
}

虽然一开始效果很好,但findBlock()在多次访问后都没有响应和超时。当我修改find​​Block()方法以返回Flux删除collectList()和block()时,它运行良好。然后我假设block()方法导致了这个问题 并且,当我修改find​​All()方法以返回List时,没有任何变化。

整个示例应用程序的源代码在这里 https://github.com/cero-t/webclient-example

&#34;资源&#34;是服务器应用程序,&#34;前面&#34;是客户端应用程序。在运行这两个应用程序之后,当我访问localhost:8080时,它运行良好,我可以随时重新加载,但是当我访问localhost:8080 / block时,它似乎运行良好,但经过多次重新加载后,它不会响应。< / p>

顺便说一下,当我添加&#34; spring-boot-starter-web&#34;依赖于&#34;前线&#34;应用程序(不是资源应用程序)pom.xml,这意味着我使用tomcat,这个问题永远不会发生。这个问题是由于Netty服务器吗?

非常感谢任何指导。

1 个答案:

答案 0 :(得分:3)

首先,我要指出,只有在从内存中提取Flux.fromIterable(items)时才建议使用items,不涉及I / O.否则,您可能正在使用阻止API来获取它 - 这可能会破坏您的被动应用程序。在这种情况下,这是一个内存列表,所以没问题。请注意,您也可以转到Flux.just(item1, item2, item3)

使用以下内容效率最高:

@GetMapping("/")
public Flux<Item> findFlux() {
  return webClient.get()
    .retrieve()
    .bodyToFlux(Item.class);
}

Item实例将以非常有效的方式即时读取/写入,解码/编码。

另一方面,这不是首选方式:

@GetMapping("/block")
public List<Item> findBlock() {
  return webClient.get()
    .retrieve()
    .bodyToFlux(Item.class)
    .collectList()
    .block(Duration.ofSeconds(10L));
}

在这种情况下,您的前端应用程序使用collectList缓存内存整个项目列表,但也阻止了可用的少数服务器线程之一。这可能会导致性能非常差,因为您的服务器可能会被阻塞等待该数据,并且无法同时为其他请求提供服务。

在这种特殊情况下情况更糟,因为应用程序完全中断。 查看控制台,我们可以看到以下内容:

WARN 3075 --- [ctor-http-nio-7] io.netty.util.concurrent.DefaultPromise  : An exception was thrown by reactor.ipc.netty.channel.PooledClientContextHandler$$Lambda$532/356589024.operationComplete()

reactor.core.Exceptions$BubblingException: java.lang.IllegalArgumentException: Channel [id: 0xab15f050, L:/127.0.0.1:59350 - R:localhost/127.0.0.1:8081] was not acquired from this ChannelPool
    at reactor.core.Exceptions.bubble(Exceptions.java:154) ~[reactor-core-3.1.3.RELEASE.jar:3.1.3.RELEASE]

这可能与应该在0.7.4.RELEASE中修复的reactor-netty client connection pool issue相关联。我不知道具体情况,但我怀疑整个连接池被破坏,因为没有从客户端连接中正确读取HTTP响应。

添加spring-boot-starter-web会使您的应用程序使用Tomcat,但它主要将您的Spring WebFlux应用程序转换为Spring MVC应用程序(现在支持一些反应式返回类型,但具有不同的运行时模型)。如果您希望使用Tomcat测试您的应用程序,可以将spring-boot-starter-tomcat添加到您的POM中,这将使用Tomcat和Spring WebFlux。