路由條
從版本 4.1 開始,Spring Integration 提供了 路由條 企業整合模式的實現。它被實現為一個 routingSlip
訊息頭,用於在端點未指定 outputChannel
時確定 AbstractMessageProducingHandler
例項中的下一個通道。此模式在複雜、動態的情況下非常有用,因為此時配置多個路由器來確定訊息流可能會變得困難。當訊息到達沒有 output-channel
的端點時,將查閱 routingSlip
來確定訊息應傳送到哪個下一個通道。當路由條用盡時,恢復正常的 replyChannel
處理。
路由條的配置表示為一種 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
處理器中。 -
RoutingSlipHeaderValueMessageProcessor
接受已解析路由條path
條目的String
陣列,並從processMessage()
返回一個以path
作為key
,以0
作為初始routingSlipIndex
的singletonMap
。
路由條 path
條目可以包含 MessageChannel
的 bean 名稱、RoutingSlipRouteStrategy
的 bean 名稱和 Spring 表示式 (SpEL)。RoutingSlipHeaderValueMessageProcessor
在首次呼叫 processMessage
時,會根據 BeanFactory
檢查每個路由條 path
條目。它將(在應用程式上下文中不是 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 配置,您可以將 RoutingSlipHeaderValueMessageProcessor
例項新增到 HeaderEnricher
bean 定義中,如下例所示
@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
時,路由條演算法的工作方式如下
-
routingSlipIndex
用於從路由條path
列表中獲取值。 -
如果來自
routingSlipIndex
的值是String
,則用於從BeanFactory
獲取 bean。 -
如果返回的 bean 是
MessageChannel
的例項,則將其用作下一個outputChannel
,並且在應答訊息頭中增加routingSlipIndex
(路由條path
條目保持不變)。 -
如果返回的 bean 是
RoutingSlipRouteStrategy
的例項,並且其getNextPath
未返回空String
,則該結果用作下一個outputChannel
的 bean 名稱。routingSlipIndex
保持不變。 -
如果
RoutingSlipRouteStrategy.getNextPath
返回空String
或null
,則增加routingSlipIndex
,並遞迴呼叫getOutputChannelFromRoutingSlip
以獲取下一個路由條path
項。 -
如果下一個路由條
path
條目不是String
,則它必須是RoutingSlipRouteStrategy
的例項。 -
當
routingSlipIndex
超出路由條path
列表的大小限制時,演算法將轉向標準replyChannel
頭的預設行為。