[英]Flux not subscribing in Spring 5 reactor
我可能遗漏了一些东西,但我无法弄清楚它是什么。
下面的代码什么都不做:
webClient.get().uri("/some/path/here").retrieve()
.bodyToMono(GetLocationsResponse.class)
.doOnNext(System.out::println)
.subscribe();
如果我尝试阻止呼叫它工作正常:
webClient.get().uri("/some/path/here").retrieve()
.bodyToMono(GetLocationsResponse.class)
.doOnNext(System.out::println)
.block();
奇怪的是,如果我“手动”创建 Flux(即不是来自 spring webClient),这可以正常工作:
Flux.just("1", "2", "3")
.filter(s -> !s.equals("2"))
.doOnNext(System.out::println)
.subscribe();
有人可以解释一下我做错了什么吗? .subscribe()
是不是应该在第一种情况下执行操作,就像在最后一种情况下一样?
谢谢!
简答
subscribe
不会阻塞当前线程,这意味着应用程序主线程可以在 Flux 发出任何元素之前完成。 所以要么使用block
要么在主线程中使用等待。
细节
调用 no-args subscribe()只是在Flux
上发出request(unbounded)
而不设置任何Subscriber
。 它通常在单独的线程中触发操作,但不会阻塞当前线程。 最有可能的是,您的主线程在WebClient
收到该单独线程中的响应之前结束,并且被动副作用doOnNext(...)
发生了。
为了说明/测试操作已启动,请在主线程中等待一段时间。 只需在subscribe()
调用之后添加以下行:
Thread.sleep(1000);
现在,在使用超时值后,您将能够看到打印的结果。
现在让我们为异步操作隐式发送一个自定义Scheduler
并等待其所有任务完成。 此外,让我们将System.out::println
作为subscribe(...)
参数而不是doOnNext
,以便完整的代码如下所示:
ExecutorService executor = Executors.newSingleThreadExecutor();
webClient.get().uri("/some/path/here").retrieve()
.bodyToMono(GetLocationsResponse.class)
.publishOn(Schedulers.fromExecutor(executor)) // next operation will go to this executor
.subscribe(System.out::println); //still non-blocking
executor.awaitTermination(1, TimeUnit.SECONDS); //block current main thread
这个例子使用了稍微不同的subscribe(Consumer) 。 最重要的是,它添加了由ExecutorService
支持的publishOn(Scheduler) 。 后者用于等待主线程中的终止。
当然,获得相同结果的更简单的方法是使用您最初提到的block()
:
webClient.get().uri("/some/path/here").retrieve() .bodyToMono(GetLocationsResponse.class) .doOnNext(System.out::println) .block();
最后,请注意您使用Flux.just(...)...subscribe()
的第三个示例 - 似乎它在您的主线程终止之前很快就完成了。 那是因为与发射单个GetLocationsResponse
元素(暗示写入请求 + 读取响应 + 解析到 POJO 的时间)相比,它需要更少的时间来发出几个String
元素。 但是,如果您将此Flux
为延迟元素,则会重现相同的行为:
Flux.just("1", "2", "3")
.filter(s -> !s.equals("2"))
.delayElements(Duration.ofMillis(500)) //this makes it stop printing in main thread
.doOnNext(System.out::println)
.subscribe();
Flux.just("1", "2", "3")
.filter(s -> !s.equals("2"))
.delayElements(Duration.ofMillis(500))
.doOnNext(System.out::println)
.blockLast(); //and that makes it printing back again
我尝试了您的样品,但未按预期工作。 为简单起见,我尝试了以下方法:
ExecutorService executorService = Executors.newSingleThreadExecutor();
Flux.just("1", "2", "3").subscribeOn(Schedulers.fromExecutor(executorService)).filter(s -> !s.equals("2"))
// .delayElements(Duration.ofMillis(500)) //this makes it stop printing in main thread
.doOnNext(System.out::println).subscribe();
try {
executorService.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
executorService.shutdown();
}
但是它总是等待十秒钟,直到终止。 通量完成后,它不会终止...您或其他人知道原因吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.