路由滑塊
從 4.1 版本開始,Spring Integration 提供了 路由滑塊 企業整合模式的實作。 它實作為 routingSlip
訊息標頭,用於在 AbstractMessageProducingHandler
實例中,當端點未指定 outputChannel
時,判斷下一個通道。 在複雜、動態的情況下,當設定多個路由器來判斷訊息流變得困難時,此模式非常有用。 當訊息到達沒有 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()
)一個singletonMap
,其中path
作為key
,0
作為初始routingSlipIndex
。
路由滑塊 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(例如,@routingSlipRoutingPojo.get(request, reply)
和 request.headers[myRoutingSlipChannel]
)來指定路由滑塊 path
條目,並避免為 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
會遞增,並且針對下一個路由滑塊path
項目以遞迴方式調用getOutputChannelFromRoutingSlip
。 -
如果下一個路由滑塊
path
條目不是String
,則它必須是RoutingSlipRouteStrategy
的實例。 -
當
routingSlipIndex
超過路由滑塊path
列表的大小時,演算法會移至標準replyChannel
標頭的預設行為。