web-dev-qa-db-fra.com

que fait Mono.defer ()?

Je suis tombé sur Mono.defer () dans du code webflux Spring

J'ai recherché la méthode dans la documentation mais je ne comprends pas l'explication:

"Créer un fournisseur Mono qui fournira un Mono cible auquel s'abonner pour chaque abonné en aval"

s'il vous plaît pourrais-je avoir une explication et un exemple. Y a-t-il un endroit avec un tas d'exemples de code Reactor (leurs tests unitaires?) Que je pourrais référencer.

merci

18
James Render

C'est un peu une simplification excessive, mais conceptuellement, les sources du réacteur sont soit paresseuses, soit avides. Les plus avancées, comme une requête HTTP, devraient être évaluées paresseusement. De l'autre côté, les plus simples comme Mono.just Ou Flux.fromIterable Sont impatients.

J'entends par là que l'appel de Mono.just(System.currentTimeMillis()) invoquera immédiatement la méthode currentTimeMillis() et capturera le résultat. Ce résultat est seulement émis par le Mono une fois qu'il est abonné. S'abonner plusieurs fois ne change pas non plus la valeur:

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

L'opérateur defer est là pour rendre cette source paresseuse, réévaluant le contenu du lambda à chaque fois qu'il y a un nouvel abonné:

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
37
Simon Baslé

avec des mots simples si vous voyez dans la première vue, c'est comme Mono.just () mais ce n'est pas le cas. lorsque vous exécutez Mono.just (), il crée immédiatement un observable (mono) et le réutilise, mais lorsque vous utilisez le report, il ne le crée pas immédiatement, il crée un nouvel observable dans chaque abonnement.

Un cas d'utilisation pour voir la différence

    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));
}

impression: 5,5,5,7

si vous voyez que mono.just a créé l'observable immédiatement et que cela ne change pas même si la valeur a changé, mais le report crée l'observable dans subscribe, vous travaillerez donc avec la valeur onsubscribe actuelle

9
Ricard Kollcaku

J'essayais defer pour un cas d'utilisation différent. A écrit le code ci-dessous pour vérifier et partager car cela pourrait aider les autres. Mon cas d'utilisation consistait à enchaîner deux Mono et à m'assurer que le premier était complet avant que le second ne soit repris. Et le second contenait un appel de blocage dont le résultat est utilisé pour répondre à une réponse Mono avec une réponse empty ou error. Sans defer, mon appel de blocage est exécuté quel que soit le résultat du premier. Mais lors de l'utilisation de defer, l'appel de blocage n'est exécuté que lorsque le premier Mono est terminé. Code ci-dessous:

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;
}

Sortie avec succeed=true - Observer la séquence "Inside Evaluator" et "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

Ci-dessous est sorti avec succeed = false - Notez que l'évaluateur n'est pas appelé.

##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
0
Pavan Kumar