java spring webflux如何在反应式世界中管理顺序业务逻辑代码
这种方法对反应友好吗
我有一个反应式控制器“save”方法调用myService。保存(请求)
服务层需要:
- jdbc save(在另一个调度程序上,因为代码被阻塞)
- 生成模板字符串(在另一个调度程序上)
- 发送电子邮件(在另一个计划程序上)
- 最后,将保存的实体返回到控制器层
我不能在一条管道中连接所有电话,或者我不知道如何实现这一点,因为我想尽快发回丢失的电话。。。。例如flatMap(templateService::generateStringTemplate)
因此,我在(1)中触发我的子操作
这是我应该如何处理的,还是有一种聪明的方法可以在一条管道中完成
下面是支持该问题的代码。谢谢
控制器层调用的服务
public Mono<Prospect> save(final Prospect prospect) {
return Mono.fromCallable(
() -> {
Prospect savedProspect = transactionTemplate.execute(status -> prospectRepository.save(prospect));
templateService.generateProspectSubscription(savedProspect)
.map(t ->
EmailPostRequest.builder()
...
.build())
.flatMap(emailService::send)
.subscribe();
return savedProspect;
})
.subscribeOn(jdbcScheduler);
}
模板服务
public Mono<String> generateProspectSubscription(final Prospect prospect) {
return Mono.fromCallable(
() -> {
Map<String, Object> model = new HashMap<>();
...
Template t = freemarkerConfig.getTemplate(WELCOME_EN_FTL);
String html = FreeMarkerTemplateUtils.processTemplateIntoString(t, model);
return html;
}
).subscribeOn(freemarkerScheduler);
}
电子邮件服务
public Mono<Void> send(final EmailPostRequest e) {
return Mono.fromCallable(
() -> {
MimeMessage message = emailSender.createMimeMessage();
MimeMessageHelper mimeHelper = new MimeMessageHelper(message,
MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,
StandardCharsets.UTF_8.name());
mimeHelper.setTo(e.getTo());
mimeHelper.setText(e.getText(), true);
mimeHelper.setSubject(e.getSubject());
mimeHelper.setFrom(new InternetAddress(e.getFrom(), e.getPersonal()));
emailSender.send(message);
return Mono.empty();
}
).subscribeOn(emailScheduler).then();
}
编辑服务 我认为这个版本的服务层更干净,但任何评论都很感谢
public Mono<Prospect> save(final Prospect prospect) {
return Mono.fromCallable(
() -> transactionTemplate.execute(status -> prospectRepository.save(prospect)))
.subscribeOn(jdbcScheduler)
.flatMap(savedProspect -> {
templateService.generateProspectSubscription(savedProspect)
.map(t ->
EmailPostRequest.builder()
...
.build())
.flatMap(emailService::send)
.subscribe();
return Mono.just(savedProspect);
}
);
}
# 1 楼答案
这种方法不是反应友好的,因为您100%地包装了阻塞库。 在这个用例中,您无法真正看到反应式运行时的好处,而且应用程序的性能可能比阻塞式运行时差
如果你的主要动机是表现,那么这可能会适得其反。 将大量阻塞I/O工作转移到专用的
Schedulers
上会带来内存(创建更多线程)和CPU(上下文切换)方面的运行时成本。如果性能和可伸缩性是您最关心的问题,那么切换到Spring MVC并在合适的地方利用Flux
/Mono
支持,甚至调用block()
操作符可能更合适如果您的主要动机是使用特定的库,比如Spring Framework的
WebClient
和Spring MVC,那么您最好在选定的位置使用.block()
操作符,而不是包装和安排所有内容