此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Integration 6.5.1spring-doc.cadn.net.cn

消息处理程序链

MessageHandlerChainMessageHandler可以将其配置为单个消息端点,同时实际委托给其他处理程序链,例如过滤器、转换器、拆分器等。 当需要以固定的线性进展连接多个处理程序时,这可以导致更简单的配置。 例如,在其他组件之前提供转换器是相当常见的。 同样,当您在链中的其他组件之前提供过滤器时,您实际上创建了一个选择性消费者。 无论哪种情况,链条都只需要一个input-channel和单个output-channel,无需为每个单独的组件定义通道。spring-doc.cadn.net.cn

MessageHandlerChain主要为 XML 配置而设计。 对于 Java DSL,一个IntegrationFlow定义可以被视为一个链式组件,但它与下面本章中描述的概念和原则无关。 有关更多信息,请参阅 Java DSL
Spring Integration 的Filter提供布尔属性:throwExceptionOnRejection. 当您在同一点对点通道上提供具有不同验收条件的多个选择性使用者时,应将此值设置为“true”(默认值为false),以便调度程序知道消息已被拒绝,并因此尝试将消息传递给其他订阅者。 如果未引发异常,则调度程序将显示消息已成功传递,即使筛选器已删除消息以防止进一步处理。 如果您确实想“删除”消息,过滤器的“丢弃通道”可能很有用,因为它确实让您有机会对删除的消息执行一些作(例如将其发送到 JMS 队列或将其写入日志)。

处理程序链简化了配置,同时在内部保持组件之间相同程度的松散耦合,如果在某个时候需要非线性排列,则修改配置是微不足道的。spring-doc.cadn.net.cn

在内部,该链被扩展为列出的端点的线性设置,由匿名通道分隔。 链中不考虑回复通道标头。 只有在调用最后一个处理程序后,生成的消息才会转发到回复通道或链的输出通道。 由于此设置,除最后一个处理程序外,所有处理程序都必须实现MessageProducer接口(提供 'setOutputChannel()' 方法)。 如果outputChannelMessageHandlerChain设置时,最后一个处理程序只需要一个输出通道。spring-doc.cadn.net.cn

与其他端点一样,output-channel是可选的。 如果链的末尾有回复消息,则输出通道优先。 但是,如果它不可用,则链处理程序会检查入站消息上的回复通道标头作为回退。

在大多数情况下,您无需实现MessageHandler你自己。 下一节重点介绍对链元素的命名空间支持。 大多数 Spring Integration 端点(例如服务激活器和转换器)都适合在MessageHandlerChain.spring-doc.cadn.net.cn

配置链

<chain>元素提供了一个input-channel属性。 如果链中的最后一个元素能够生成回复消息(可选),它还支持output-channel属性。 然后,子元素是Filter、转换器、分路器和服务激活器。 最后一个元素也可以是路由器或出站通道适配器。 以下示例显示了链定义:spring-doc.cadn.net.cn

<int:chain input-channel="input" output-channel="output">
    <int:filter ref="someSelector" throw-exception-on-rejection="true"/>
    <int:header-enricher>
        <int:header name="thing1" value="thing2"/>
    </int:header-enricher>
    <int:service-activator ref="someService" method="someMethod"/>
</int:chain>

<header-enricher>前面示例中使用的元素设置名为thing1值为thing2在消息上。 标头扩充器是Transformer仅触及标头值。 您可以通过实现MessageHandler这完成了标头修改并将其作为 bean 进行连接,但标头丰富器是一个更简单的选项。spring-doc.cadn.net.cn

<chain>可以配置为消息流的最后一个“封闭框”使用者。 对于此解决方案,您可以将其放在<链的末尾>一些<outbound-channel-adapter>,如以下示例所示:spring-doc.cadn.net.cn

<int:chain input-channel="input">
    <int-xml:marshalling-transformer marshaller="marshaller" result-type="StringResult" />
    <int:service-activator ref="someService" method="someMethod"/>
    <int:header-enricher>
        <int:header name="thing1" value="thing2"/>
    </int:header-enricher>
    <int:logging-channel-adapter level="INFO" log-full-message="true"/>
</int:chain>
不允许的属性和元素

某些属性,例如orderinput-channel不允许在链中使用的组件上指定。 轮询器子元素也是如此。spring-doc.cadn.net.cn

对于 Spring Integration 核心组件,XML 模式本身强制执行其中一些约束。 但是,对于非核心组件或您自己的自定义组件,这些约束由 XML 命名空间解析器强制执行,而不是由 XML 架构强制执行。spring-doc.cadn.net.cn

这些 XML 命名空间解析器约束是随 Spring Integration 2.2 添加的。 如果您尝试使用不允许的属性和元素,XML 命名空间解析器会抛出一个BeanDefinitionParsingException.spring-doc.cadn.net.cn

使用 'id' 属性

从 Spring Integration 3.0 开始,如果为链元素提供id属性,则元素的 bean 名称是链的idid元素本身。 没有的元素id属性未注册为 bean,但每个属性都被赋予一个componentName这包括链条id. 请考虑以下示例:spring-doc.cadn.net.cn

<int:chain id="somethingChain" input-channel="input">
    <int:service-activator id="somethingService" ref="someService" method="someMethod"/>
    <int:object-to-json-transformer/>
</int:chain>

在前面的示例中:spring-doc.cadn.net.cn

  • <chain>root 元素有一个id“某物链”。 因此,AbstractEndpoint实现 (PollingConsumerEventDrivenConsumer,具体取决于input-channeltype) bean 将此值作为其 bean 名称。spring-doc.cadn.net.cn

  • MessageHandlerChainbean 获取一个 bean 别名(“somethingChain.handler”),它允许从BeanFactory.spring-doc.cadn.net.cn

  • <service-activator>不是一个成熟的消息传递端点(它不是PollingConsumerEventDrivenConsumer). 这是一个MessageHandler<chain>. 在这种情况下,使用BeanFactory是 'somethingChain$child.somethingService.handler'。spring-doc.cadn.net.cn

  • componentNameServiceActivatingHandler采用相同的值,但没有 '.handler' 后缀。 它变为 'somethingChain$child.somethingService'。spring-doc.cadn.net.cn

  • 最后<chain>子组件,<object-to-json-transformer>,没有id属性。 其componentName基于它在<chain>. 在本例中,它是 'somethingChain$child#1'。 (名称的最后一个元素是链中的顺序,以“#0”开头)。 请注意,此转换器未在应用程序上下文中注册为 bean,因此它不会获得beanName. 然而,它的componentName具有可用于日志记录和其他目的的值。spring-doc.cadn.net.cn

id属性<chain>元素使它们有资格进行 JMX 导出,并且可以在消息历史记录中进行跟踪。 您可以从BeanFactory如前所述,使用适当的 bean 名称。spring-doc.cadn.net.cn

提供显式id属性<chain>元素来简化日志中子组件的识别,并提供从BeanFactory等。

从链中调用链

有时,您需要从链内对另一条链进行嵌套调用,然后返回并在原始链中继续执行。 为此,可以通过包含 <gateway> 元素来使用消息网关,如以下示例所示:spring-doc.cadn.net.cn

<int:chain id="main-chain" input-channel="in" output-channel="out">
    <int:header-enricher>
      <int:header name="name" value="Many" />
    </int:header-enricher>
    <int:service-activator>
      <bean class="org.foo.SampleService" />
    </int:service-activator>
    <int:gateway request-channel="inputA"/>
</int:chain>

<int:chain id="nested-chain-a" input-channel="inputA">
    <int:header-enricher>
        <int:header name="name" value="Moe" />
    </int:header-enricher>
    <int:gateway request-channel="inputB"/>
    <int:service-activator>
        <bean class="org.foo.SampleService" />
    </int:service-activator>
</int:chain>

<int:chain id="nested-chain-b" input-channel="inputB">
    <int:header-enricher>
        <int:header name="name" value="Jack" />
    </int:header-enricher>
    <int:service-activator>
        <bean class="org.foo.SampleService" />
    </int:service-activator>
</int:chain>

在前面的示例中,nested-chain-a在末尾调用main-chain由在那里配置的“网关”元素进行处理。 在nested-chain-a,调用nested-chain-b是在标头富集后制作的。 然后流返回以完成执行nested-chain-b. 最后,流返回到main-chain. 当<gateway>元素在链中定义,它不需要service-interface属性。 相反,它将消息置于当前状态,并将其放置在request-channel属性。 当该网关启动的下游流完成时,一个Message返回到网关并在当前链中继续其旅程。spring-doc.cadn.net.cn