|
如需使用最新稳定版本,请使用 Spring Integration 7.0.4! |
路由滑槽
从Spring Integration 4.1版本开始,提供了routingSlipAbstractMessageProducingHandleroutputChanneloutput-channelroutingSlipreplyChannel
配置路由条的设置以HeaderEnricher选项呈现——这是一个分号分隔的路由条,包含path个条目,如下例所示:
<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>
该示例包含:
-
使用
<context:property-placeholder>配置来演示路由条目的键可以在path中指定为可解析的键。 -
<header-enricher><routing-slip>子元素用于填充RoutingSlipHeaderValueMessageProcessor到HeaderEnricher处理程序。 -
The
RoutingSlipHeaderValueMessageProcessor接受一个已解析的路由单path条目的String数组,并从processMessage()返回一个singletonMap,其中path作为key,0作为初始routingSlipIndex。
路由表 path 条目可以包含 MessageChannel 个 Bean 名称、RoutingSlipRouteStrategy 个 Bean 名称以及 Spring 表达式(SpEL)。
RoutingSlipHeaderValueMessageProcessor 会在首次 processMessage 调用时,将每个路由表 path 条目与 BeanFactory 进行校验。
它会将应用上下文中非 Bean 名称的条目转换为 ExpressionEvaluatingRoutingSlipRouteStrategy 实例。
RoutingSlipRouteStrategy 条目会被多次调用,直到它们返回 null 或空的 String。
由于路由单涉及getOutputChannel流程,我们拥有一个请求 - 回复上下文。
已引入RoutingSlipRouteStrategy用于确定下一个使用requestMessage和reply对象的outputChannel。
该策略的实现应作为 Bean 注册在应用上下文中,其 Bean 名称将在路由单的path中使用。
提供了ExpressionEvaluatingRoutingSlipRouteStrategy实现。
它接受一个 SpEL 表达式,并使用内部的ExpressionEvaluatingRoutingSlipRouteStrategy.RequestAndReply对象作为评估上下文的根对象。
这是为了避免为每次ExpressionEvaluatingRoutingSlipRouteStrategy.getNextPath()调用创建EvaluationContext的开销。
它是一个简单的 Java Bean,包含两个属性:Message<?> request和Object reply。
通过此表达式实现,我们可以使用 SpEL 指定路由单path条目(例如@routingSlipRoutingPojo.get(request, reply)和request.headers[myRoutingSlipChannel]),从而避免为RoutingSlipRouteStrategy定义 Bean。
参数 requestMessage 始终是一个 Message<?>。 根据上下文,回复对象可能是一个 Message<?>、一个 AbstractIntegrationMessageBuilder,或者是一个任意的应用程序域对象(例如,当它是由服务激活器调用的 POJO 方法返回时)。 在前两种情况下,使用 SpEL(或 Java 实现)时,通常的 Message 属性(payload 和 headers)是可用的。 对于一个任意的域对象,这些属性不可用。 因此,在将路由单与 POJO 方法结合使用时要小心,如果结果用于确定下一个路径。 |
如果在分布式环境中涉及路由单,我们建议不要在路由单中使用内联表达式 path。
此建议适用于各种分布式环境,例如跨 JVM 应用程序、通过消息代理(如AMQP 支持或JMS 支持)使用request-reply,或在集成流程中使用持久化MessageStore(消息存储)。
该框架使用RoutingSlipHeaderValueMessageProcessor将其转换为ExpressionEvaluatingRoutingSlipRouteStrategy对象,并在routingSlip消息头中使用它们。
由于此类不是Serializable(因为它依赖于BeanFactory,所以无法实现),整个Message变得不可序列化,在任何分布式操作中,最终都会导致NotSerializableException。
为了克服这一限制,请注册一个包含所需 SpEL 的ExpressionEvaluatingRoutingSlipRouteStrategy Bean,并在路由单path配置中使用其 Bean 名称。 |
对于Java配置,您可以向HeaderEnricher bean定义添加一个RoutingSlipHeaderValueMessageProcessor实例,如下例所示:
@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 算法的工作方式如下:
-
使用
routingSlipIndex可以从路由条目path列表中获取一个值。 -
如果来自
routingSlipIndex的值为String,则使用该值从BeanFactory获取一个bean。 -
如果返回的bean是一个
MessageChannel的实例,它将被用作下一个outputChannel,并且在回复消息头中递增routingSlipIndex(路由条path的条目保持不变)。 -
如果返回的bean是一个
RoutingSlipRouteStrategy实例,并且其getNextPath不返回空String,那么这个结果将被用作下一个outputChannel的bean名称。 而routingSlipIndex保持不变。 -
如果
RoutingSlipRouteStrategy.getNextPath返回空的String或null,则routingSlipIndex递增,并且对下一个路由条目path调用getOutputChannelFromRoutingSlip进行递归。 -
如果下一个路由条目
path不是String,那么它必须是RoutingSlipRouteStrategy的实例。 -
当数字
routingSlipIndex超过路由条目path列表的大小时,算法将切换到标准replyChannel头的默认行为。