Mono switchIfEmpty() is always called

前端 未结 1 650

I have two methods.
Main method:

@PostMapping(\"/login\")
public Mono> loginUser(@RequestBody final LoginUs         


        
1条回答
  •  天涯浪人
    2020-12-25 13:19

    It's because switchIfEmpty accepts Mono "by value". Meaning that even before you subscribe to your mono, this alternative mono's evaluation is already triggered.

    Imagine a method like this:

    Mono asyncAlternative() {
        return Mono.fromFuture(CompletableFuture.supplyAsync(() -> {
            System.out.println("Hi there");
            return "Alternative";
        }));
    }
    

    If you define your code like this:

    Mono result = Mono.just("Some payload").switchIfEmpty(asyncAlternative());
    

    It'll always trigger alternative no matter what during stream construction. To address this you can defer evaluation of a second mono by using Mono.defer

    Mono result = Mono.just("Some payload")
            .switchIfEmpty(Mono.defer(() -> asyncAlternative()));
    

    This way it will only print "Hi there" when alternative is requested

    UPD:

    Elaborating a little on my answer. The problem you're facing is not related to Reactor but to Java language itself and how it resolves method parameters. Let's examine the code from the first example I provided.

    Mono result = Mono.just("Some payload").switchIfEmpty(asyncAlternative());
    

    We can rewrite this into:

    Mono firstMono = Mono.just("Some payload");
    Mono alternativeMono = asyncAlternative();
    Mono result = firstMono.switchIfEmpty(alternativeMono);
    

    These two code snippets are semantically equivalent. We can continue unwrapping them to see where the problem lies:

    Mono firstMono = Mono.just("Some payload");
    CompletableFuture alternativePromise = CompletableFuture.supplyAsync(() -> {
            System.out.println("Hi there");
            return "Alternative";
        }); // future computation already tiggered
    Mono alternativeMono = Mono.fromFuture(alternativePromise);
    Mono result = firstMono.switchIfEmpty(alternativeMono);
    

    As you can see future computation was already triggered at the point when we start composing our Mono types. To prevent unwanted computations we can wrap our future into a defered evaluation:

    Mono result = Mono.just("Some payload")
            .switchIfEmpty(Mono.defer(() -> asyncAlternative()));
    

    Which will unwrap into

    Mono firstMono = Mono.just("Some payload");
    Mono alternativeMono = Mono.defer(() -> Mono.fromFuture(CompletableFuture.supplyAsync(() -> {
            System.out.println("Hi there");
            return "Alternative";
        }))); // future computation defered
    Mono result = firstMono.switchIfEmpty(alternativeMono);
    

    In second example the future is trapped in a lazy supplier and is scheduled for execution only when it will be requested.

    0 讨论(0)
提交回复
热议问题