3.1.3 Channel Interceptors
One of the advantages of a messaging architecture is the ability to provide common behavior and capture(提取) meaningful(有意义的) information about the messages passing through the system in a non-invasive(非入侵的) way. Since theMessagesare being sent to and received fromMessageChannels, those channels provide an opportunity(时机) for intercepting(拦截) the send and receive operations. TheChannelInterceptorstrategy interface provides methods for each of those operations:
(PS:作为消息传输架构的另外一个高级特性就是通过非入侵的方式从传输的消息中提供有效的数据。 当消息通过 消息通道 从开始发送到被接受,那些通道提供在发送和接受是的拦截机制。 接口ChannelInterceptor 提供 上述环节的拦截方法。)
public interface ChannelInterceptor { Message preSend(Message message, MessageChannel channel); void postSend(Message message, MessageChannel channel, boolean sent); boolean preReceive(MessageChannel channel); Message postReceive(Message message, MessageChannel channel);}After implementing the interface, registering the interceptor with a channel is just a matter of calling: 一个实现该接口的实例,通过如下的方式注册到 指定的 channel 中。
channel.addInterceptor(someChannelInterceptor);
The methods that return a Message instance can be used for transforming the Message or can return 'null' to prevent(防止) further processing (of course, any of the methods can throw a RuntimeException). Also, thepreReceivemethod can return 'false' to prevent the receive operation from proceeding.
(PS:上述方法姜返回一个 消息 实例用于传输中的消息抑或返回 null 值,防止之后的环节处理。 preReceive()允许返回 false 值,从而避免接收者继续进行操作。)
Note |
---|
Keep in mind thatreceive()calls are only relevant(相应的) forPollableChannels. In fact theSubscribableChannelinterface does not even define areceive()method. The reason for this is that when a Message is sent to aSubscribableChannelit will be sent directly to one or more subscribers depending on the type of channel (e.g. a PublishSubscribeChannel sends to all of its subscribers). Therefore()因此, thepreReceive(..)andpostReceive(..)interceptor methods are only invoked when the interceptor is applied to aPollableChannel. (PS:切记,receive()方法只能被PollableChannels 接口调用。原因是当消息发送给 SubscribableChannel 是,会被直接 发送到一个或者多个订阅者。因侧 preReceive(..) 与 postReceive(..) 这两个拦截方法及仅仅作用于 PollableChannel 调用 receive 方法前后进行拦截。 ) |
Spring Integration also provides an implementation of the pattern. It is a simple interceptor that sends the Message to another channel without otherwise altering the existing flow(不影响当前流程). It can be very useful for debugging and monitoring(监控). An example is shown in the section called “Wire Tap”.
(PS: Spring Integration 同样也提供了 窃听 模式的拦截机制,它是一种简单的拦截实现,当发送的消息被他拦截时, 他会发送一个消息到指定的 channel中,而不应喜爱那个原先的 channle处理流程。 这个对于程序调试以及监控是很有用的,可以异步执行哦)
Because it is rarely(很少) necessary to implement all of the interceptor methods, aChannelInterceptorAdapterclass is also available for sub-classing. It provides no-op methods (thevoidmethod is empty, theMessagereturning methods return the Message as-is, and thebooleanmethod returnstrue). Therefore, it is often easiest to extend that class and just implement the method(s) that you need as in the following example.
(PS:由于在实际情况下,很少需要实现全部的interceptor接口定义的方法。所以系统默认提供了 ChannelInterceptorAdapter 适配器,他实现了全部接口的空方法 ...... 在实际开发的过程中,开发者按需重载指定的方法,从而实现拦截的功能。)
public class CountingChannelInterceptor extends ChannelInterceptorAdapter { private final AtomicInteger sendCount = new AtomicInteger(); @Override public Message preSend(Message message, MessageChannel channel) { sendCount.incrementAndGet(); return message; }}
Tip |
---|
The order of invocation for the interceptor methods depends on the type of channel. As described above, the queue-based channels are the only ones where the receive method is intercepted in the first place. Additionally(另外), the relationship between send and receive interception depends on the timing of separate(分开,分离) sender and receiver threads. For example, if a receiver is already blocked while waiting for a message the order could be: preSend, preReceive, postReceive, postSend. However, if a receiver polls after the sender has placed(放置) a message on the channel and already returned, the order would be: preSend, postSend, (some-time-elapses) preReceive, postReceive. The time that elapses in such a case depends on a number of factors and is therefore generally unpredictable (in fact, the receive may never happen!). Obviously(明显), the type of queue also plays a role (e.g. rendezvous vs. priority). The bottom line is that you cannot rely on(依靠) the order beyond the fact that preSend will precede postSend and preReceive will precede(优先于) postReceive. (PS: 拦截器调用的拦截方法 依赖于不同类型的channel,如上所述, 基于队列模式channels 唯一的receive 会在第一时间被拦截。 另外,发送与接受时的拦截调用取决不各自操作的线程。例如,当一个接收者已经被阻塞 而等待一个消息的到达,其调用顺序可能是: preSend, preReceive, postReceive, postSend。 而另外一种场景:当一个消息到达channel并且已经已经返回给sender,这时如果一个消费者轮询,则调用顺序 如下: preSend, postSend, 有时也会有例外:preReceive, postReceive。 中间很费解,我也不是很清楚。 ) |
3.1.4 MessagingTemplate
As you will see when the endpoints and their various configuration options are introduced, Spring Integration provides a foundation for messaging components that enables non-invasive invocation of your application code from the messaging system. However, sometimes it is necessary to invoke the messaging system from your application code. For convenience(方便) when implementing such use-cases, Spring Integration provides aMessagingTemplatethat supports a variety of operations across the Message Channels, including request/reply scenarios. For example, it is possible to send a request and wait for a reply.
(PS: 到目前位置,大致介绍了endpoints 以及 它涉及的各种配置,Spring Integration 提供一种非侵入式的基础的消息传输组件。有一种这样的情况,那就是你不得不在你的应用 代码中调用消息系统的功能。为方便起见(方便)在实施这样的使用情况下, Spring集成提供了一个MessagingTemplate支持在消息渠道的各种操作, 包括请求/应答的情况。例如,它可以发送一个请求,并等待答复。)
MessagingTemplate template = new MessagingTemplate();Message reply = template.sendAndReceive(someChannel, new GenericMessage("test"));
In that example, a temporary anonymous channel would be created internally by the template. The 'sendTimeout' and 'receiveTimeout' properties may also be set on the template, and other exchange types are also supported.
(PS:在该示例中,系统默认创建了一个临时的匿名的channel被 MessagingTemplate。 其中 sendTimeout 与 receiveTimeout 属性同样被 MessagingTemplate 赋值。获取其他类型的修改支持。)
public boolean send(final MessageChannel channel, final Message message) { ... }public Message sendAndReceive(final MessageChannel channel, final Message request) { .. }public Message receive(final PollableChannel channel) { ... }Note
A less invasive approach that allows you to invoke simple interfaces with payload and/or header values instead of Message instances is described in Section 7.2.1, “Enter the GatewayProxyFactoryBean”.
(PS: 还有一种更加简介的途径来通过调允许你访问 有效负载 或者 消息头的的简单接口 而不是消息实体)