簡體   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