Java Mono.defer()做什么?

Java Mono.defer()做什么?,java,spring-webflux,project-reactor,Java,Spring Webflux,Project Reactor,我在一些SpringWebFlux代码中遇到Mono.defer() 我在文档中查找了方法,但不理解解释: “创建一个Mono提供商,该提供商将提供一个目标Mono以供订阅 对于每个下游用户” 请给我一个解释和一个例子。有没有一个地方有一堆反应堆示例代码(它们的单元测试?)可以供我参考 用简单的话谢谢你 如果您在第一个视图中看到,它类似于Mono.just(),但不是。 当您运行Mono.just()时,它会立即创建一个可观察对象(Mono)并重用它,但当您使用defer时,它不会立即创建它,而

我在一些SpringWebFlux代码中遇到Mono.defer()

我在文档中查找了方法,但不理解解释:

“创建一个Mono提供商,该提供商将提供一个目标Mono以供订阅 对于每个下游用户”

请给我一个解释和一个例子。有没有一个地方有一堆反应堆示例代码(它们的单元测试?)可以供我参考

用简单的话谢谢你 如果您在第一个视图中看到,它类似于Mono.just(),但不是。 当您运行Mono.just()时,它会立即创建一个可观察对象(Mono)并重用它,但当您使用defer时,它不会立即创建它,而是在每个订阅中创建新的可观察对象

一个用例可以看出区别

    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));
}
inta=5;
@凌驾
公共无效运行(字符串…参数)引发异常{
Mono monoJust=Mono.just(a);
Mono 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立即创建了可观测值,即使值发生了变化,它也不会发生变化,但延迟在subscribe中创建了可观测值,因此您将使用当前的onsubscribe值,这有点过于简单,但从概念上讲,Reactor源要么懒惰,要么急切。更高级的请求(如HTTP请求)需要延迟评估。另一方面,像
Mono.just
Flux.fromIterable
等最简单的软件都是渴望的

我的意思是,调用
Mono.just(System.currentTimeMillis())
将立即调用
currentTimeMillis()
方法并捕获结果。所述结果仅在订阅后由
Mono
发出。多次订阅也不会更改值:

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

我试图
推迟
一个不同的用例。写了下面的代码来检查和分享,因为它可能会帮助其他人。我的用例是链接两个
Mono
s,并确保在使用第二个之前完成第一个。第二个包含一个阻塞调用,其结果用于响应
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=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

初学者的简单答案:

在monoJust变量上调用subscribe时,它将打印一个随机整数三次。但在调用monoDefer变量上的subscribe时,它每次都可以打印一个随机数

   Mono<Integer> justMono = Mono.just((new Random()).nextInt(10));

    //this will print same random number thrice
    for(int i=0;i<3;i++)
        justMono.subscribe(x -> {System.out.println("Just Mono: " + x);});

    Mono<Integer> deferMono = Mono.defer(() -> Mono.just((new Random()).nextInt(10)));

    //this might print three different random numbers
    for(int i=0;i<3;i++)
        deferMono.subscribe(x -> {System.out.println("Defer Mono: " + x);});
Mono-justMono=Mono.just((new Random()).nextInt(10));
//这将打印相同的随机数三次
对于(inti=0;i{System.out.println(“justmono:+x”);});
Mono deferMono=Mono.defer(()->Mono.just((new Random()).nextInt(10));
//这可能会打印三个不同的随机数
对于(inti=0;i{System.out.println(“延迟Mono:+x”);});
在Mono中,当第一次订阅发生时,just()实例化只发生一次。在Mono中,每次调用subscribe时都会发生.defer()实例化

有关更多参考信息,请查看:
3:15分钟

您检查过javadoc了吗?Flux/Monos上的大多数方法都包含一个它如何处理反应流的图表。我个人觉得这种语言很难理解;一些琐碎的代码示例会对我有所帮助。我正在克隆反应堆核心项目,并将查看单元测试,看看这是否会有所帮助。示例代码、链接和RxJava的Observable在阅读示例时应替换为Mono或Flux的注释的组合帮助了我。反应堆代码很难阅读和预测,至少在最初,这些图表也是另一种语言,我需要一个教程:)谢谢@RichardKollcaku,mono有一个底层状态的快照,defer说,每次调用subscribe时获取当前状态。你的解释不完全正确。没有“创建新的可观察对象”这样的东西。公正和延迟创建一个可观察的。Mono.defer评估供应商功能时,Mono.just返回每个订阅的值。我说的不是作为对象可观察,而是作为逻辑可观察。单核细胞是可以观察到的。只需创建新的可观察,这意味着创建新的单声道@htn@jrender如果是
Mono.just()
,它实际上无法应用于状态快照。在本例中,他使用了一个基元类型,因此结果不会改变,但如果您使用一个对象(如list)并在两个订阅之间对其进行变异(添加一个新值),您将得到两个不同的结果,但它仍然是同一个对象。@RicardKollcaku别担心,我很清楚它是如何工作的。Spring Reactor中不存在术语
Observable
,因此对我来说Observable=Mono | Flux。当我理解这个答案时,我从不喜欢这种解释,因为它有点暗示它的库选择
Mono.just(System.currentTimeMillis())
在被调用时将立即执行。但这就是java的工作原理,没人会想到方法调用会被库删除和延迟。是的,这就是java的工作原理,没有包装在lambda中的方法调用不能神奇地变为懒惰。我不想让图书馆做出“选择”@SimonBaslé我写的Netty HTTP客户端(为什么我不能使用Reactor Netty是另一个主题)返回流量。我不希望任何排放发生,直到有人苏醒过来
##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
   Mono<Integer> justMono = Mono.just((new Random()).nextInt(10));

    //this will print same random number thrice
    for(int i=0;i<3;i++)
        justMono.subscribe(x -> {System.out.println("Just Mono: " + x);});

    Mono<Integer> deferMono = Mono.defer(() -> Mono.just((new Random()).nextInt(10)));

    //this might print three different random numbers
    for(int i=0;i<3;i++)
        deferMono.subscribe(x -> {System.out.println("Defer Mono: " + x);});