消息传递体系结构的一个优点是能够提供常见行为,并以非侵入性方式捕获有关通过系统传递的消息的有意义信息。 由于实例是发送到实例和从实例接收的,因此这些通道提供了拦截发送和接收操作的机会。 策略接口(如下面的清单所示)为这些操作中的每一个提供了方法:MessageMessageChannelChannelInterceptorspring-doc.cn

public interface ChannelInterceptor {

    Message<?> preSend(Message<?> message, MessageChannel channel);

    void postSend(Message<?> message, MessageChannel channel, boolean sent);

    void afterSendCompletion(Message<?> message, MessageChannel channel, boolean sent, Exception ex);

    boolean preReceive(MessageChannel channel);

    Message<?> postReceive(Message<?> message, MessageChannel channel);

    void afterReceiveCompletion(Message<?> message, MessageChannel channel, Exception ex);
}

实现接口后,向 channel 注册拦截器只需进行以下调用即可:spring-doc.cn

channel.addInterceptor(someChannelInterceptor);

返回实例的方法可用于转换 或 可以返回 'null' 以防止进一步处理(当然,任何方法都可以抛出 a )。 此外,该方法还可以返回以防止接收操作继续进行。MessageMessageRuntimeExceptionpreReceivefalsespring-doc.cn

请记住,调用仅与 相关。 事实上,该接口甚至没有定义方法。 这样做的原因是,当 a 被发送到 时,它会直接发送给零个或多个订阅者,具体取决于通道的类型(例如, A 发送给其所有订阅者)。 因此,仅当将侦听器应用于 .receive()PollableChannelsSubscribableChannelreceive()MessageSubscribableChannelPublishSubscribeChannelpreReceive(…​)postReceive(…​)afterReceiveCompletion(…​)PollableChannel
请记住,调用仅与 相关。 事实上,该接口甚至没有定义方法。 这样做的原因是,当 a 被发送到 时,它会直接发送给零个或多个订阅者,具体取决于通道的类型(例如, A 发送给其所有订阅者)。 因此,仅当将侦听器应用于 .receive()PollableChannelsSubscribableChannelreceive()MessageSubscribableChannelPublishSubscribeChannelpreReceive(…​)postReceive(…​)afterReceiveCompletion(…​)PollableChannel

Spring 集成还提供了 Wire Tap 模式的实现。 它是一个简单的拦截器,可以将 发送到另一个通道,而不会改变现有流。 它对于调试和监控非常有用。 Wire Tap 中显示了一个示例。Messagespring-doc.cn

由于很少需要实现所有拦截器方法,因此该接口提供无操作方法(返回方法没有代码,-returning 方法按原样返回,方法返回)。voidMessageMessagebooleantruespring-doc.cn

拦截器方法的调用 Sequences 取决于通道的类型。 如前所述,基于队列的通道是唯一首先拦截该方法的通道。 此外,发送和接收拦截之间的关系取决于单独的发送方和接收方线程的计时。 例如,如果接收方在等待消息时已被阻止,则顺序可能如下所示:、、、、。 但是,如果接收方在发送方在通道上放置消息并已返回后进行轮询,则顺序将如下所示:、(经过一段时间)、、。 在这种情况下,经过的时间取决于许多因素,因此通常是不可预测的(事实上,接收可能永远不会发生)。 队列的类型也起着一定的作用(例如,rendezvous 与 priority)。 简而言之,您不能依赖超出 precedes 和 precedes 的事实之外的顺序。receive()preSendpreReceivepostReceivepostSendpreSendpostSendpreReceivepostReceivepreSendpostSendpreReceivepostReceive
拦截器方法的调用 Sequences 取决于通道的类型。 如前所述,基于队列的通道是唯一首先拦截该方法的通道。 此外,发送和接收拦截之间的关系取决于单独的发送方和接收方线程的计时。 例如,如果接收方在等待消息时已被阻止,则顺序可能如下所示:、、、、。 但是,如果接收方在发送方在通道上放置消息并已返回后进行轮询,则顺序将如下所示:、(经过一段时间)、、。 在这种情况下,经过的时间取决于许多因素,因此通常是不可预测的(事实上,接收可能永远不会发生)。 队列的类型也起着一定的作用(例如,rendezvous 与 priority)。 简而言之,您不能依赖超出 precedes 和 precedes 的事实之外的顺序。receive()preSendpreReceivepostReceivepostSendpreSendpostSendpreReceivepostReceivepreSendpostSendpreReceivepostReceive

从 Spring Framework 4.1 和 Spring Integration 4.1 开始,提供了新的方法:和. 它们在调用后调用,而不管引发的任何异常如何,这允许资源清理。 请注意,通道以与 initial 和 calls 相反的顺序调用列表中的这些方法。ChannelInterceptorafterSendCompletion()afterReceiveCompletion()send()' and 'receive()ChannelInterceptorpreSend()preReceive()spring-doc.cn

从版本 5.1 开始,全局通道拦截器现在适用于动态注册的通道 - 例如通过使用 Java DSL 初始化的 bean 或在使用 Java DSL 时初始化的 bean。 以前,在刷新应用程序上下文后创建 bean 时,不会应用拦截器。beanFactory.initializeBean()IntegrationFlowContextspring-doc.cn

此外,从版本 5.1 开始,当未收到消息时,不再调用;不再需要检查 . 以前,该方法被调用。 如果你有一个依赖于先前行为的拦截器,请改为实现,因为无论是否收到消息,都会调用该方法。ChannelInterceptor.postReceive()nullMessage<?>afterReceiveCompleted()spring-doc.cn

从版本 5.2 开始,Spring Messaging 模块已被弃用,现在它扩展了该模块以实现向后兼容性。ChannelInterceptorAwareInterceptableChannel
从版本 5.2 开始,Spring Messaging 模块已被弃用,现在它扩展了该模块以实现向后兼容性。ChannelInterceptorAwareInterceptableChannel