声明检查 (Claim Check)

在之前的章节中,我们介绍了几个内容丰富组件,它们可以帮助你处理消息缺少数据的情况。我们还讨论了内容过滤,它允许你从消息中删除数据项。但是,有时我们需要暂时隐藏数据。例如,在分布式系统中,我们可能会收到包含非常大负载的消息。一些中间的消息处理步骤可能不需要访问此负载,而有些步骤可能只需要访问某些报头,因此在每个处理步骤中都携带大型消息负载可能会导致性能下降,可能会产生安全风险,并可能使调试更加困难。

存储在库中”(或认领凭证)模式描述了一种机制,允许你将数据存储在众所周知的位置,同时仅保留指向数据位置的指针(认领凭证)。你可以将该指针作为新消息的有效负载传递,从而允许消息流中的任何组件在需要时获取实际数据。这种方法与挂号邮件过程非常相似,你可以在邮箱中收到认领凭证,然后必须去邮局认领你的实际包裹。它也与航班后的行李认领或酒店中的行李认领相同。

Spring Integration 提供两种类型的认领凭证转换器

  • 传入认领凭证转换器

  • 传出认领凭证转换器

可以使用方便的基于命名空间的机制来配置它们。

传入认领凭证转换器

传入认领凭证转换器通过将其存储在其message-store属性标识的消息存储中来转换传入的消息。以下示例定义了一个传入认领凭证转换器

<int:claim-check-in id="checkin"
        input-channel="checkinChannel"
        message-store="testMessageStore"
        output-channel="output"/>

在前面的配置中,接收到的input-channel上的消息会持久保存到message-store属性标识的消息存储中,并使用生成的 ID 建立索引。该 ID 是该消息的认领凭证。认领凭证也成为发送到output-channel的新(转换后)消息的有效负载。

现在,假设在某些时候你确实需要访问实际消息。你可以手动访问消息存储并获取消息的内容,或者你可以使用相同的方法(创建转换器),只是现在你使用传出认领凭证转换器将认领凭证转换为实际消息。

以下列表提供了传入认领凭证转换器所有可用参数的概述

<int:claim-check-in auto-startup="true"             (1)
                    id=""                           (2)
                    input-channel=""                (3)
                    message-store="messageStore"    (4)
                    order=""                        (5)
                    output-channel=""               (6)
                    send-timeout="">                (7)
    <int:poller></int:poller>                       (8)
</int:claim-check-in>
1 生命周期属性,指示此组件是否应在应用程序上下文启动期间启动。默认为true。此属性在Chain元素内不可用。可选。
2 标识底层 bean 定义(MessageTransformingHandler)的 ID。此属性在Chain元素内不可用。可选。
3 此端点的接收消息通道。此属性在Chain元素内不可用。可选。
4 对将由此认领凭证转换器使用的MessageStore的引用。如果未指定,则默认引用为名为messageStore的 bean。可选。
5 当此端点连接到通道作为订阅者时,指定调用顺序。当该通道使用failover调度策略时,这尤其重要。当此端点本身是具有队列的通道的轮询使用者时,它没有效果。此属性在Chain元素内不可用。可选。
6 标识在消息由此端点处理后发送消息的消息通道。此属性在Chain元素内不可用。可选。
7 指定向输出通道发送回复消息时要等待的最长时间(以毫秒为单位)。默认为30秒。此属性在Chain元素内不可用。可选。
8 定义轮询器。此元素在Chain元素内不可用。可选。

传出认领凭证转换器

传出认领凭证转换器允许你将具有认领凭证有效负载的消息转换为具有原始内容作为其有效负载的消息。

<int:claim-check-out id="checkout"
        input-channel="checkoutChannel"
        message-store="testMessageStore"
        output-channel="output"/>

在前面的配置中,接收到的input-channel上的消息应具有认领凭证作为其有效负载。传出认领凭证转换器通过查询消息存储中由提供的认领凭证标识的消息,将其转换为具有原始有效负载的消息。然后,它将新签出的消息发送到output-channel

以下列表提供了传出认领凭证转换器所有可用参数的概述

<int:claim-check-out auto-startup="true"             (1)
                     id=""                           (2)
                     input-channel=""                (3)
                     message-store="messageStore"    (4)
                     order=""                        (5)
                     output-channel=""               (6)
                     remove-message="false"          (7)
                     send-timeout="">                (8)
    <int:poller></int:poller>                        (9)
</int:claim-check-out>
1 生命周期属性,指示此组件是否应在应用程序上下文启动期间启动。默认为true。此属性在Chain元素内不可用。可选。
2 标识底层 bean 定义(MessageTransformingHandler)的 ID。此属性在Chain元素内不可用。可选。
3 此端点的接收消息通道。此属性在Chain元素内不可用。可选。
4 对将由此认领凭证转换器使用的MessageStore的引用。如果未指定,则默认引用为名为messageStore的 bean。可选。
5 当此端点连接到通道作为订阅者时,指定调用顺序。当该通道使用failover调度策略时,这尤其重要。当此端点本身是具有队列的通道的轮询使用者时,它没有效果。此属性在Chain元素内不可用。可选。
6 标识在消息由此端点处理后发送消息的消息通道。此属性在Chain元素内不可用。可选。
7 如果设置为true,则消息将从此转换器中从MessageStore中删除。当消息只能“认领”一次时,此设置很有用。默认为false。可选。
8 指定向输出通道发送回复消息时要等待的最长时间(以毫秒为单位)。默认为30秒。此属性在Chain元素内不可用。可选。
9 定义轮询器。此元素在Chain元素内不可用。可选。

一次认领

有时,特定消息必须仅认领一次。作为类比,考虑处理飞机行李的过程。你在出发时托运行李,并在到达时认领行李。行李一旦被认领,就不能再次认领,除非先将其再次托运。为了适应这种情况,我们在claim-check-out转换器上引入了一个remove-message布尔属性。此属性默认为false。但是,如果设置为true,则认领的消息将从MessageStore中删除,以便无法再次认领。

此功能会影响存储空间,尤其是在基于内存MapSimpleMessageStore的情况下,如果不删除消息,最终可能会导致OutOfMemoryException。因此,如果你不希望进行多次认领,我们建议你将remove-message属性的值设置为true。以下示例显示了如何使用remove-message属性

<int:claim-check-out id="checkout"
        input-channel="checkoutChannel"
        message-store="testMessageStore"
        output-channel="output"
        remove-message="true"/>

关于消息存储的一些说明

虽然我们很少关心认领凭证的细节(只要它们有效即可),但你应该知道,Spring Integration 中实际认领凭证(指针)的当前实现使用 UUID 来确保唯一性。

org.springframework.integration.store.MessageStore是用于存储和检索消息的策略接口。Spring Integration 提供了它的两个方便的实现

  • SimpleMessageStore:基于内存Map的实现(默认,适合测试)

  • JdbcMessageStore:通过 JDBC 使用关系数据库的实现