如何迭代Flux并与Mono混合

时间:2017-10-14 11:23:35

标签: java reactive-programming project-reactor spring-webflux

我有一个用例,我应该向用户发送电子邮件。 首先我创建电子邮件正文。

Mono<String> emailBody = ...cache();

然后我选择用户并将电子邮件发送给他们:

Flux.fromIterable(userRepository.findAllByRole(Role.USER))
            .map(User::getEmail)
            .doOnNext(email -> sendEmail(email, emailBody.block(), massSendingSubject))
            .subscribe();

我不喜欢

  1. 如果没有cache()方法,emailBody Mono会在每个迭代步骤中计算。
  2. 要获取emailBody值,我使用的是emailBody.block(),但是在Flux流程中可能存在被动方式而不是调用块方法?

1 个答案:

答案 0 :(得分:5)

此代码示例中存在几个问题。 我假设这是一个反应性的Web应用程序。

首先,目前尚不清楚如何创建电子邮件正文;你从数据库或远程服务中获取东西?如果它主要是CPU绑定(而不是I / O),那么您不需要将其包装成反应类型。现在,如果它应该是Publisher的包装并且所有用户的电子邮件内容都相同,那么使用cache运算符并不是一个糟糕的选择。

此外,Flux.fromIterable(userRepository.findAllByRole(Role.USER))建议您从被动上下文中调用阻塞存储库。

您应该从不doOn***运算符中执行繁重的I / O操作。这些是用于伐木或轻微副作用的操作。你需要.block()这一事实是另一个线索,你将阻止你的整个被动管道。

上一篇:您不应该在Web应用程序中的任何位置调用subscribe。如果这绑定到HTTP请求,则基本上触发响应管道而不保证资源或完成。调用subscribe会触发管道,但不会等到它完成(此方法返回Disposable)。

更“典型”的样本如下:

Flux<User> users = userRepository.findAllByRole(Role.USER);
String emailBody = emailContentGenerator.createEmail();


// sendEmail() should return Mono<Void> to signal when the send operation is done
Mono<Void> sendEmailsOperation = users
     .flatMap(user -> sendEmail(user.getEmail(), emailBody, subject))
     .then();

// something else should subscribe to that reactive type,
// you could plug that as a return value of a Controller for example

如果你以某种方式坚持使用阻塞组件(例如sendEmail组件),则应该在特定的调度程序上安排这些阻塞操作,以避免阻塞整个被动管道。为此,请查看Schedulers section on the reactor reference documentation