いくつかのSpring webfluxコードでMono.defer()に遭遇しました
私はドキュメントでメソッドを調べましたが、説明がわかりません:
「サブスクライバーダウンストリームごとにサブスクライブするターゲットMonoを提供するMonoプロバイダーを作成します」
説明と例をお願いします。私が参照する可能性のある一連のReactorサンプルコード(そのユニットテスト?)がある場所はありますか?.
ありがとう
これは少し単純化しすぎていますが、概念的には、Reactorのソースは遅延または熱心です。 HTTPリクエストのようなより高度なものは、遅延評価されることが期待されています。反対に、_Mono.just
_や_Flux.fromIterable
_のような最も単純なものは熱心です。
つまり、Mono.just(System.currentTimeMillis())
を呼び出すと、すぐにcurrentTimeMillis()
メソッドが呼び出され、結果がキャプチャされます。上記の結果は、サブスクライブされた後のMono
によるemittedのみです。複数回登録しても値は変わりません。
_Mono<Long> clock = Mono.just(System.currentTimeMillis());
//time == t0
Thread.sleep(10_000);
//time == t10
clock.block(); //we use block for demonstration purposes, returns t0
Thread.sleep(7_000);
//time == t17
clock.block(); //we re-subscribe to clock, still returns t0
_
defer
演算子は、このソースを遅延させるためにあり、ラムダのコンテンツを再評価します新しいサブスクライバーが存在するたびに:
_Mono<Long> clock = Mono.defer(() -> Mono.just(System.currentTimeMillis()));
//time == t0
Thread.sleep(10_000);
//time == t10
clock.block(); //invoked currentTimeMillis() here and returns t10
Thread.sleep(7_000);
//time == t17
clock.block(); //invoke currentTimeMillis() once again here and returns t17
_
簡単な言葉で言うと、最初のビューで見るとMono.just()のようですが、そうではありません。 Mono.just()を実行するとすぐにObservable(Mono)が作成されて再利用されますが、deferを使用するとすぐには作成されず、すべてのサブスクライブで新しいObservableが作成されます。
違いを確認するための1つの使用例
int a = 5;
@Override
public void run(String... args) throws Exception {
Mono<Integer> monoJust = Mono.just(a);
Mono<Integer> monoDefer = Mono.defer(() -> Mono.just(a));
monoJust.subscribe(integer1 -> System.out.println(integer1));
monoDefer.subscribe(integer1 -> System.out.println(integer1));
a = 7;
monoJust.subscribe(integer1 -> System.out.println(integer1));
monoDefer.subscribe(integer1 -> System.out.println(integer1));
}
印刷:5、5、5、7
mono.justがオブザーバブルをすぐに作成し、値が変更されても変更されないことがわかりますが、延期はサブスクライブでオブザーバブルを作成するため、現在のオンサブスクライブ値で作業します
私は別のユースケースでdefer
を試みていました。他の人を助けるかもしれないので、以下のコードを書いてチェックして共有してください。私の使用例は、2つのMono
sをチェーンして、最初のものが完了してから2番目のものが使用されるようにすることでした。また、2番目のブロックには、Mono
またはempty
応答でerror
に応答するために使用されるブロッキング呼び出しが含まれていました。 defer
がないと、最初の呼び出しの結果に関係なく、ブロッキング呼び出しが実行されます。ただし、defer
の使用中は、最初のMono
が完了したときにのみブロッキング呼び出しが実行されます。以下のコード:
public static void main(String[] args) {
long cur = System.currentTimeMillis();
boolean succeed = true;
Mono<Integer> monoJust = Mono.create(consumer -> {
System.out.println("MonoJust inside " + (System.currentTimeMillis() - cur));
if (succeed) {
consumer.success(1);
} else {
consumer.error(new RuntimeException("aaa"));
}
});
Mono<String> monoJustStr = Mono.create(consumer -> {
System.out.println("MonoJustStr inside: " + (System.currentTimeMillis() - cur));
consumer.success("one");
});
System.out.println("##1##: Begin");
monoJust.then(evaluator() ? Mono.empty() : monoJustStr).subscribe(d -> System.out.println("##1##: "+d), e-> System.err.println(e));
System.out.println("##1##: Done: "+(System.currentTimeMillis() - cur));
System.out.println("\n\n\n##2##: Begin");
monoJust.then(Mono.defer(() -> evaluator() ? Mono.empty() : monoJustStr)).subscribe(d -> System.out.println("##2##: "+d), e-> System.err.println(e));
System.out.println("##2##: Done: " + (System.currentTimeMillis() - cur));
}
private static boolean evaluator() {
System.out.println("Inside Evaluator");
return false;
}
succeed=true
を使用した出力-「Inside Evaluator」と「MonoJust inside」のシーケンスを確認します
##1##: Begin
Inside Evaluator
MonoJust inside 540
MonoJustStr inside: 542
##1##: one
##1##: Done: 542
##2##: Begin
MonoJust inside 544
Inside Evaluator
MonoJustStr inside: 544
##2##: one
##2##: Done: 544
以下はsucceed = false
の出力です。エバリュエーターが呼び出されないことに注意してください。
##1##: Begin
Inside Evaluator
MonoJust inside 565
Java.lang.RuntimeException: aaa
##1##: Done: 567
##2##: Begin
MonoJust inside 569
Java.lang.RuntimeException: aaa
##2##: Done: 569