Project Reactor中doOnComplete()与subscribe()第三个参数的区别
Project Reactor中doOnComplete()与subscribe()完成回调的差异及适用场景
二者虽然都会响应流的完成信号,但在绑定关系、复用性、职责定位上有本质区别,具体适用场景可以从以下几点区分:
1. 与流生命周期的绑定层级不同
doOnComplete()是流操作符链的中间副作用操作,它的回调会在完成信号流经该操作符节点时触发,属于流本身的一部分。在你的示例代码中,完成信号会先触发doOnComplete()的日志,再传递到订阅者触发subscribe()的完成回调。subscribe()的第三个参数是订阅者的终端回调,仅当整个流的所有操作执行完毕,且订阅者收到完成信号时才会触发,属于单次订阅的收尾逻辑。
2. 复用性差异
- 如果你将包含
doOnComplete()的Flux/Mono实例复用(比如多次调用subscribe()),每次订阅都会触发doOnComplete()的回调,因为它是流的固有逻辑。 subscribe()的完成回调是单次订阅专属的,不同的订阅可以传入不同的回调逻辑,相互独立,不会随流的复用而重复执行。
举个复用场景的例子:
Flux<Integer> sharedFlux = Flux.range(1, 2) .doOnComplete(() -> log.info("[全局流完成]")); // 第一次订阅 sharedFlux.subscribe( data -> log.info("[订阅1] 数据: {}", data), null, () -> log.info("[订阅1] 任务完成") ); // 第二次订阅 sharedFlux.subscribe( data -> log.info("[订阅2] 数据: {}", data), null, () -> log.info("[订阅2] 任务完成") );
执行后会打印两次[全局流完成],以及各自订阅的完成日志,体现了两者的复用性差异。
3. 职责定位不同
doOnComplete()适合处理流的通用逻辑:比如流级别的资源清理(关闭数据库连接、释放临时缓存)、全局日志打点、流状态重置等,这些逻辑是所有订阅该流的场景都需要执行的。subscribe()完成回调适合处理单次订阅的业务逻辑:比如通知用户本次任务完成、更新当前页面的UI状态、记录单次订阅的业务日志等,这些逻辑和具体的订阅行为绑定,不同订阅可能需要不同的处理。
4. 异常场景的表现一致
如果流在中途抛出异常,完成信号会被终止,doOnComplete()和subscribe()的完成回调都不会执行,此时会触发subscribe()的错误回调(第二个参数)。
内容的提问来源于stack exchange,提问作者superpil
相关产品推荐
相关产品推荐

