有人可以帮助我以反应式重构这段代码吗?
userService.deleteAll().then().block();
userService.saveAll(Flux.just(candidate, tech, pm, hr)).then().block();
我认为onNext(…)
then(…)
方法可以简化此实现。
非常感谢。
答案 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,因为您通常不希望自己处理同步。