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