如需使用最新稳定版本,请使用 Spring Integration 7.0.4spring-doc.cadn.net.cn

路由滑槽

从Spring Integration 4.1版本开始,提供了路由条企业集成模式的实现。 它被实现为一个routingSlip消息头,在AbstractMessageProducingHandler实例中用于确定消息流的下一个通道,当端点没有指定outputChannel时。 在复杂且动态的情况下,此模式非常有用,因为配置多个路由器来决定消息流向可能会变得困难。 当一个消息到达一个端点而该端点没有指定output-channel时,将查阅routingSlip以确定应发送给哪个下一个通道。 当路由条用尽后,正常的replyChannel处理将继续进行。spring-doc.cadn.net.cn

配置路由条的设置以HeaderEnricher选项呈现——这是一个分号分隔的路由条,包含path个条目,如下例所示:spring-doc.cadn.net.cn

<util:properties id="properties">
    <beans:prop key="myRoutePath1">channel1</beans:prop>
    <beans:prop key="myRoutePath2">request.headers[myRoutingSlipChannel]</beans:prop>
</util:properties>

<context:property-placeholder properties-ref="properties"/>

<header-enricher input-channel="input" output-channel="process">
    <routing-slip
        value="${myRoutePath1}; @routingSlipRoutingPojo.get(request, reply);
               routingSlipRoutingStrategy; ${myRoutePath2}; finishChannel"/>
</header-enricher>

该示例包含:spring-doc.cadn.net.cn

  • 使用<context:property-placeholder>配置来演示路由条目的键可以在path中指定为可解析的键。spring-doc.cadn.net.cn

  • <header-enricher> <routing-slip> 子元素用于填充 RoutingSlipHeaderValueMessageProcessorHeaderEnricher 处理程序。spring-doc.cadn.net.cn

  • The RoutingSlipHeaderValueMessageProcessor 接受一个已解析的路由单 path 条目的 String 数组,并从 processMessage() 返回一个 singletonMap,其中 path 作为 key0 作为初始 routingSlipIndexspring-doc.cadn.net.cn

路由表 path 条目可以包含 MessageChannel 个 Bean 名称、RoutingSlipRouteStrategy 个 Bean 名称以及 Spring 表达式(SpEL)。 RoutingSlipHeaderValueMessageProcessor 会在首次 processMessage 调用时,将每个路由表 path 条目与 BeanFactory 进行校验。 它会将应用上下文中非 Bean 名称的条目转换为 ExpressionEvaluatingRoutingSlipRouteStrategy 实例。 RoutingSlipRouteStrategy 条目会被多次调用,直到它们返回 null 或空的 Stringspring-doc.cadn.net.cn

由于路由单涉及getOutputChannel流程,我们拥有一个请求 - 回复上下文。 已引入RoutingSlipRouteStrategy用于确定下一个使用requestMessagereply对象的outputChannel。 该策略的实现应作为 Bean 注册在应用上下文中,其 Bean 名称将在路由单的path中使用。 提供了ExpressionEvaluatingRoutingSlipRouteStrategy实现。 它接受一个 SpEL 表达式,并使用内部的ExpressionEvaluatingRoutingSlipRouteStrategy.RequestAndReply对象作为评估上下文的根对象。 这是为了避免为每次ExpressionEvaluatingRoutingSlipRouteStrategy.getNextPath()调用创建EvaluationContext的开销。 它是一个简单的 Java Bean,包含两个属性:Message<?> requestObject reply。 通过此表达式实现,我们可以使用 SpEL 指定路由单path条目(例如@routingSlipRoutingPojo.get(request, reply)request.headers[myRoutingSlipChannel]),从而避免为RoutingSlipRouteStrategy定义 Bean。spring-doc.cadn.net.cn

参数 requestMessage 始终是一个 Message<?>。 根据上下文,回复对象可能是一个 Message<?>、一个 AbstractIntegrationMessageBuilder,或者是一个任意的应用程序域对象(例如,当它是由服务激活器调用的 POJO 方法返回时)。 在前两种情况下,使用 SpEL(或 Java 实现)时,通常的 Message 属性(payloadheaders)是可用的。 对于一个任意的域对象,这些属性不可用。 因此,在将路由单与 POJO 方法结合使用时要小心,如果结果用于确定下一个路径。
如果在分布式环境中涉及路由单,我们建议不要在路由单中使用内联表达式 path。 此建议适用于各种分布式环境,例如跨 JVM 应用程序、通过消息代理(如AMQP 支持JMS 支持)使用request-reply,或在集成流程中使用持久化MessageStore消息存储)。 该框架使用RoutingSlipHeaderValueMessageProcessor将其转换为ExpressionEvaluatingRoutingSlipRouteStrategy对象,并在routingSlip消息头中使用它们。 由于此类不是Serializable(因为它依赖于BeanFactory,所以无法实现),整个Message变得不可序列化,在任何分布式操作中,最终都会导致NotSerializableException。 为了克服这一限制,请注册一个包含所需 SpEL 的ExpressionEvaluatingRoutingSlipRouteStrategy Bean,并在路由单path配置中使用其 Bean 名称。

对于Java配置,您可以向HeaderEnricher bean定义添加一个RoutingSlipHeaderValueMessageProcessor实例,如下例所示:spring-doc.cadn.net.cn

@Bean
@Transformer(inputChannel = "routingSlipHeaderChannel")
public HeaderEnricher headerEnricher() {
    return new HeaderEnricher(Collections.singletonMap(IntegrationMessageHeaderAccessor.ROUTING_SLIP,
            new RoutingSlipHeaderValueMessageProcessor("myRoutePath1",
                                                       "@routingSlipRoutingPojo.get(request, reply)",
                                                       "routingSlipRoutingStrategy",
                                                       "request.headers[myRoutingSlipChannel]",
                                                       "finishChannel")));
}

当端点生成回复且未定义outputChannel时,路由 Slip 算法的工作方式如下:spring-doc.cadn.net.cn

  • 使用routingSlipIndex可以从路由条目path列表中获取一个值。spring-doc.cadn.net.cn

  • 如果来自routingSlipIndex的值为String,则使用该值从BeanFactory获取一个bean。spring-doc.cadn.net.cn

  • 如果返回的bean是一个MessageChannel的实例,它将被用作下一个outputChannel,并且在回复消息头中递增routingSlipIndex(路由条 path 的条目保持不变)。spring-doc.cadn.net.cn

  • 如果返回的bean是一个RoutingSlipRouteStrategy实例,并且其getNextPath不返回空String,那么这个结果将被用作下一个outputChannel的bean名称。 而routingSlipIndex保持不变。spring-doc.cadn.net.cn

  • 如果RoutingSlipRouteStrategy.getNextPath返回空的Stringnull,则routingSlipIndex递增,并且对下一个路由条目path调用getOutputChannelFromRoutingSlip进行递归。spring-doc.cadn.net.cn

  • 如果下一个路由条目path不是String,那么它必须是RoutingSlipRouteStrategy的实例。spring-doc.cadn.net.cn

  • 当数字routingSlipIndex超过路由条目path列表的大小时,算法将切换到标准replyChannel头的默认行为。spring-doc.cadn.net.cn