繁体   English   中英

Flux 未订阅 Spring 5 反应堆

[英]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.

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