无法在订阅的单声道上接收onNext和onComplete

时间:2017-03-10 02:31:42

标签: project-reactor

我正在尝试反应堆库,而且我无法弄清楚为什么下面的单声道永远不会返回onNext或onComplete调用。我想我错过了非常微不足道的事情。这是一个示例代码。

MyServiceService service = new MyServiceService();
    service.save("id")
            .map(myUserMono -> new MyUser(myUserMono.getName().toUpperCase(), myUserMono.getId().toUpperCase()))
            .subscribe(new Subscriber<MyUser>() {
                @Override
                public void onSubscribe(Subscription s) {
                    System.out.println("Subscribed!" + Thread.currentThread().getName());
                }

                @Override
                public void onNext(MyUser myUser) {
                    System.out.println("OnNext on thread " + Thread.currentThread().getName());

                }

                @Override
                public void onError(Throwable t) {
                    System.out.println("onError!" + Thread.currentThread().getName());

                }

                @Override
                public void onComplete() {
                    System.out.println("onCompleted!" + Thread.currentThread().getName());

                }
            });


}

private static class MyServiceService {
    private Repository myRepo = new Repository();

    public Mono<MyUser> save(String userId) {
        return myRepo.save(userId);
    }
}

private static class Repository {

    public Mono<MyUser> save(String userId) {
        return Mono.create(myUserMonoSink -> {
            Future<MyUser> submit = exe.submit(() -> this.blockingMethod(userId));
            ListenableFuture<MyUser> myUserListenableFuture = JdkFutureAdapters.listenInPoolThread(submit);
            Futures.addCallback(myUserListenableFuture, new FutureCallback<MyUser>() {
                @Override
                public void onSuccess(MyUser result) {
                    myUserMonoSink.success(result);
                }

                @Override
                public void onFailure(Throwable t) {
                    myUserMonoSink.error(t);
                }
            });
        });
    }

    private MyUser blockingMethod(String userId) throws InterruptedException {
        Thread.sleep(5000);
        return new MyUser("blocking", userId);
    }
}

以上代码仅打印Subcribed!main。我无法弄清楚为什么未来的回调不是通过myUserMonoSink.success

推动价值的原因

2 个答案:

答案 0 :(得分:3)

要记住的重要一点是,大多数情况下,FluxMono 异步

订阅后,保存用户的异步处理在执行程序中启动,但在.subscribe(...)之后在主代码中继续执行。

所以main线程退出,在将任何内容推送到Mono之前终止测试。

[侧边栏]:什么时候同步?

当数据源是Flux / Mono同步工厂方法时。但是增加的先决条件是操作员链的其余部分不会切换执行上下文。这可能是明确地(您使用publishOnsubscribeOn运算符)或隐式(某些运算符,如与时间相关的运算符,例如。delayElements)在单独的Scheduler上运行)。

简单地说,您的源是在ExecutorService的{​​{1}}个线程中运行的,因此exe确实是异步的。另一方面,您的代码段在Mono上运行。

如何解决问题

要在实验中观察main的正确行为(与生产中的完全异步代码相反),可以使用以下几种方法:

  • 使用system.out.printlns保留Mono,但在subscribenew CountDownLatch(1)中添加.countDown() onCompleteonError之后的倒计时锁定await
  • 使用subscribe代替.log().block()。您将失去对每个事件执行操作的自定义,但.subscribe(...)将为您打印出这些内容(前提是您已配置了日志框架)。 log()将恢复为阻止模式,并完成我上面用CountDownLatch建议的内容。它返回值一旦可用,或者在出现错误时抛出block()
  • 而不是Exception您可以使用log()方法自定义日志记录或其他副作用(对于几乎所有类型的事件+事件组合,都有自定义日志或其他副作用,例如。{{1} },.doOnXXX(...) ...)

如果您正在进行单元测试,请使用doOnSubscribe项目中的doOnNext。当您拨打StepVerifier时,它会订阅flux / mono并等待事件。请参阅参考指南chapter on testing(以及参考指南的其余部分)。

答案 1 :(得分:1)

问题是在创建的匿名类onSubscribe方法中什么都不做。 如果您查看LambdaSubscriber的实现,它会请求一些事件。 此外,它更容易扩展BaseSubscriber,因为它有一些预定义的逻辑。

所以您的订阅者实施将是:

MyServiceService service = new MyServiceService();
service.save("id")
        .map(myUserMono -> new MyUser(myUserMono.getName().toUpperCase(), myUserMono.getId().toUpperCase()))
        .subscribe(new BaseSubscriber<MyUser>() {
                @Override
                protected void hookOnSubscribe(Subscription subscription) {
                    System.out.println("Subscribed!" + Thread.currentThread().getName());
                    request(1); // or requestUnbounded();
                }

                @Override
                protected void hookOnNext(MyUser myUser) {
                    System.out.println("OnNext on thread " + Thread.currentThread().getName());

                    // request(1); // if wasn't called requestUnbounded()  2
                }

                @Override
                protected void hookOnComplete() {
                    System.out.println("onCompleted!" + Thread.currentThread().getName());
                }

                @Override
                protected void hookOnError(Throwable throwable) {
                    System.out.println("onError!" + Thread.currentThread().getName());
                }

            });

也许它不是最好的实施方式,我也是反应堆的新手。

Simon的回答对测试异步代码有很好的解释。