对于最新的稳定版本,请使用 Spring Integration 6.4.3! |
通道拦截器
消息传递体系结构的一个优点是能够提供常见行为,并以非侵入性方式捕获有关通过系统传递的消息的有意义信息。
由于Message
实例发送到和接收自MessageChannel
实例中,这些通道提供了拦截 Send 和 Receive作的机会。
这ChannelInterceptor
strategy 接口,如下面的清单所示,为这些作中的每一个都提供了方法:
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 注册拦截器只需进行以下调用即可:
channel.addInterceptor(someChannelInterceptor);
返回Message
实例可用于转换Message
或者可以返回 'null' 以防止进一步处理(当然,任何方法都可以抛出RuntimeException
).
此外,preReceive
method 可以返回false
以防止接收作继续进行。
请记住,receive() 呼叫仅与PollableChannels .
事实上,SubscribableChannel interface 甚至没有定义receive() 方法。
这样做的原因是,当Message 发送到SubscribableChannel ,它会直接发送给零个或多个订阅者,具体取决于通道类型(例如
一个PublishSubscribeChannel 发送到其所有订阅者)。
因此,preReceive(…) ,postReceive(…) 和afterReceiveCompletion(…) 仅当拦截器应用于PollableChannel . |
Spring 集成还提供了 Wire Tap 模式的实现。
它是一个简单的拦截器,它发送Message
到另一个通道,而无需更改现有流。
它对于调试和监控非常有用。
Wire Tap 中显示了一个示例。
由于很少需要实现所有拦截器方法,因此该接口提供了无作方法(返回void
method 没有代码,则Message
-returning 方法返回Message
as-is,并且boolean
method 返回true
).
拦截器方法的调用 Sequences 取决于通道的类型。
如前所述,基于队列的通道是唯一receive() 方法首先被拦截。
此外,发送和接收拦截之间的关系取决于单独的发送方和接收方线程的计时。
例如,如果接收方在等待消息时已被阻止,则顺序可能如下所示:preSend ,preReceive ,postReceive ,postSend .
但是,如果接收方在发送方在通道上放置消息并已返回后进行轮询,则顺序将如下所示:preSend ,postSend (有时已经过去了)、preReceive ,postReceive .
在这种情况下,经过的时间取决于许多因素,因此通常是不可预测的(事实上,接收可能永远不会发生)。
队列的类型也起着一定的作用(例如,rendezvous 与 priority)。
简而言之,除了preSend 之前postSend 和preReceive 之前postReceive . |
从 Spring Framework 4.1 和 Spring Integration 4.1 开始,ChannelInterceptor
提供了新的方法:afterSendCompletion()
和afterReceiveCompletion()
.
它们在send()' and 'receive()
调用,而不管引发的任何异常如何,这允许进行资源清理。
请注意,通道在ChannelInterceptor
列表与初始preSend()
和preReceive()
调用。
从版本 5.1 开始,全局通道拦截器现在适用于动态注册的通道 - 例如通过使用beanFactory.initializeBean()
或IntegrationFlowContext
使用 Java DSL 时。
以前,在刷新应用程序上下文后创建 bean 时,不会应用拦截器。
此外,从版本 5.1 开始,ChannelInterceptor.postReceive()
未收到消息时不再调用;不再需要检查null
Message<?>
.
以前,该方法被调用。
如果你有一个依赖于先前行为的拦截器,请实现afterReceiveCompleted()
相反,因为该方法被调用,无论是否收到消息。
从版本 5.2 开始,ChannelInterceptorAware 已弃用,取而代之的是InterceptableChannel 从 Spring Messaging 模块,它现在扩展了该模块以实现向后兼容性。 |