有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java spring webflux如何在反应式世界中管理顺序业务逻辑代码

这种方法对反应友好吗

我有一个反应式控制器“save”方法调用myService。保存(请求)

服务层需要:

  1. jdbc save(在另一个调度程序上,因为代码被阻塞)
  2. 生成模板字符串(在另一个调度程序上)
  3. 发送电子邮件(在另一个计划程序上)
  4. 最后,将保存的实体返回到控制器层

我不能在一条管道中连接所有电话,或者我不知道如何实现这一点,因为我想尽快发回丢失的电话。。。。例如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) 个答案

  1. # 1 楼答案

    这种方法不是反应友好的,因为您100%地包装了阻塞库。 在这个用例中,您无法真正看到反应式运行时的好处,而且应用程序的性能可能比阻塞式运行时差

    如果你的主要动机是表现,那么这可能会适得其反。 将大量阻塞I/O工作转移到专用的Schedulers上会带来内存(创建更多线程)和CPU(上下文切换)方面的运行时成本。如果性能和可伸缩性是您最关心的问题,那么切换到Spring MVC并在合适的地方利用Flux/Mono支持,甚至调用block()操作符可能更合适

    如果您的主要动机是使用特定的库,比如Spring Framework的WebClient和Spring MVC,那么您最好在选定的位置使用.block()操作符,而不是包装和安排所有内容