将ReactiveCrudRepository.deleteAll()。block()重构为非阻塞代码

时间:2017-09-06 12:48:18

标签: spring spring-data reactive-programming project-reactor

有人可以帮助我以反应式重构这段代码吗?

userService.deleteAll().then().block();
userService.saveAll(Flux.just(candidate, tech, pm, hr)).then().block();

我认为onNext(…) then(…)方法可以简化此实现。 非常感谢。

1 个答案:

答案 0 :(得分:4)

看起来你正在寻找

    Mono<Void> mono = userService.deleteAll()
            .thenMany(userService.saveAll(Flux.just(candidate, tech, pm, hr)))
            .then();

订阅生成的Publisher(在这种情况下为Mono)是启动执行的自然方式。

一旦设置了反应序列,就应该考虑如何执行它了。订阅序列是开始执行的自然方法(.subscribe()),但这通常不是您在自己的代码中执行的操作,除非您有充分的理由这样做。根据源Publisher(在您的情况下是MongoDB / Couchbase / Cassandra驱动程序之一),订阅会启动一个非阻塞进程,该进程在对.subscribe()的调用完成后继续运行。通常,您的基础架构(容器)会触发订阅并处理同步(通过.subscribe(Subscription))。在Spring WebFlux控制器的上下文中,您的代码可能如下所示:

@PostMapping("…")
public Mono<Void> save() {

    Mono<Void> mono = userService.deleteAll()
            .thenMany(userService.saveAll(Flux.just(candidate, tech, pm, hr)))
            .then();

    return mono;
}

通过传递Mono<Void>作为服务器响应的一部分,您可以移交被动序列以便执行。底层容器订阅Publisher并在订阅终止后立即写入HTTP响应(即同步部分)。

如果您想自己执行反应序列,那么您需要自己处理同步。 Mono.block() / Flux.block()是在隔离环境中同步调用的方便方法,但除了非常好的理由外,这也是你不应该做的事情。一个很好的理由可能是您没有周围的容器,并且代码没有大规模执行。使用阻塞调用会失去反应式执行模型为您提供的好处,因为在执行终止之前,线程会被阻塞。

关于.deleteAll()的最后一句话:有时您需要通过删除或插入数据来初始化组件或数据库状态。所有这些初始化器恰好在同步API(Spring的afterPropertiesSet(),JSR 250的@PostConstruct)中执行。在特定的上下文中,您宁愿坚持使用命令式API,因为您通常不希望自己处理同步。