路由滑塊

從 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 作為 key0 作為初始 routingSlipIndex

路由滑塊 path 條目可以包含 MessageChannel bean 名稱、RoutingSlipRouteStrategy bean 名稱和 Spring 運算式 (SpEL)。 RoutingSlipHeaderValueMessageProcessor 在第一次 processMessage 調用時,針對 BeanFactory 檢查每個路由滑塊 path 條目。 它將條目(應用程式上下文中不是 bean 名稱的條目)轉換為 ExpressionEvaluatingRoutingSlipRouteStrategy 實例。 RoutingSlipRouteStrategy 條目會被多次調用,直到它們傳回 null 或空 String

由於路由滑塊參與 getOutputChannel 流程,我們有請求-回覆上下文。 引入 RoutingSlipRouteStrategy 是為了判斷下一個使用 requestMessagereply 物件的 outputChannel。 此策略的實作應在應用程式上下文中註冊為 bean,並且其 bean 名稱用於路由滑塊 path 中。 提供了 ExpressionEvaluatingRoutingSlipRouteStrategy 實作。 它接受 SpEL 運算式,並且內部 ExpressionEvaluatingRoutingSlipRouteStrategy.RequestAndReply 物件用作評估上下文的根物件。 這是為了避免每次調用 ExpressionEvaluatingRoutingSlipRouteStrategy.getNextPath() 時建立 EvaluationContext 的開銷。 它是一個簡單的 Java bean,具有兩個屬性:Message<?> requestObject reply。 使用此運算式實作,我們可以使用 SpEL(例如,@routingSlipRoutingPojo.get(request, reply)request.headers[myRoutingSlipChannel])來指定路由滑塊 path 條目,並避免為 RoutingSlipRouteStrategy 定義 bean。

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 設定,您可以將 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 傳回空 Stringnull,則 routingSlipIndex 會遞增,並且針對下一個路由滑塊 path 項目以遞迴方式調用 getOutputChannelFromRoutingSlip

  • 如果下一個路由滑塊 path 條目不是 String,則它必須是 RoutingSlipRouteStrategy 的實例。

  • routingSlipIndex 超過路由滑塊 path 列表的大小時,演算法會移至標準 replyChannel 標頭的預設行為。