跳到主要内容

使用全局钩子

Doubao 中英对照 Using Global Hooks

目录

Reactor 还有另一类可配置的回调,它们会在各种情况下被 Reactor 操作符调用。这些回调都在 Hooks 类中设置,共分为三类:

1. 丢弃钩子​

当某个操作符的数据源不遵守 Reactive Streams 规范时,就会调用丢弃钩子。这类错误不在正常的执行路径之内(也就是说,它们无法通过 onError 传播)。

典型情形是:某个 Publisher 在已经对操作符调用过 onCompleted 之后,又对它调用了 onNext。在这种情况下,这个 onNext 的值会被丢弃。多余的 onError 信号也是如此。

对应的钩子——onNextDropped 和 onErrorDropped——让您可以为这些丢弃行为提供一个全局 Consumer。例如,您可以用它记录丢弃事件,并在需要时清理与某个值相关联的资源(因为这个值永远不会到达响应式链路的其余部分)。

连续两次设置这些钩子是叠加生效的:您提供的每一个 consumer 都会被调用。可以使用 Hooks.resetOn*Dropped() 方法把这些钩子完全重置为默认状态。

2. 内部错误钩子​

其中一个钩子是 onOperatorError,当操作符在执行其 onNext、onError 和 onComplete 方法的过程中抛出意外的 Exception 时,就会被操作符调用。

与上一类钩子不同,这一类仍然处于正常的执行路径之内。一个典型例子是:map 操作符的映射函数抛出了 Exception(例如除以零)。此时仍然可以走常规的 onError 通道,而操作符正是这样做的。

首先,它把这个 Exception 传递给 onOperatorError。该钩子让您可以检查错误(以及相关的那个有问题的值,如果有的话),并修改这个 Exception。当然,您也可以顺便做点别的事,比如记录日志后返回原始的 Exception。

请注意,onOperatorError 钩子可以设置多次。您可以为某个特定的 BiFunction 提供一个 String 标识符,之后再用不同的 key 调用时,这些函数会被串联起来并全部执行。另一方面,如果两次复用同一个 key,则会替换掉您之前设置的那个函数。

因此,默认的钩子行为既可以被完全重置(使用 Hooks.resetOnOperatorError()),也可以只针对某个特定的 key 做部分重置(使用 Hooks.resetOnOperatorError(String))。

3. 组装钩子​

这些钩子与操作符的生命周期挂钩。它们在组装(即实例化)一条操作符链时被调用。onEachOperator 让您可以在操作符被组装进链路时,通过返回一个不同的 Publisher 来动态地修改每一个操作符。onLastOperator 与之类似,区别只在于它只作用于 subscribe 调用之前链路中的最后一个操作符。

如果您想用一个横切的 Subscriber 实现来装饰所有操作符,可以借助 Operators#lift* 系列方法,它们能帮您应对 Reactor 中各种类型的 Publisher(Flux、Mono、ParallelFlux、GroupedFlux 和 ConnectableFlux),以及它们的 Fuseable 版本。

与 onOperatorError 一样,这些钩子是累积式的,并且可以用一个 key 来标识。它们同样可以被部分或完全重置。

4. 钩子预设​

Hooks 工具类提供了两个预设钩子。它们是默认行为的替代方案,您只需调用对应的方法即可启用,而无需自己编写钩子:

  • onNextDroppedFail():onNextDropped 过去会抛出 Exceptions.failWithCancel() 异常。现在它默认在 DEBUG 级别记录被丢弃的值。要恢复过去那种抛出异常的默认行为,请使用 onNextDroppedFail()。

  • onOperatorDebug():此方法会启用调试模式。它挂接在 onOperatorError 钩子上,因此调用 resetOnOperatorError() 也会一并重置它。您也可以使用 resetOnOperatorDebug() 单独重置它,因为它内部使用了一个特定的 key。