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