訊息處理器鏈

MessageHandlerChainMessageHandler 的一個實現,它可以被配置為一個單一的訊息端點,同時實際上委託給一個由其他處理器組成的鏈,例如過濾器、轉換器、拆分器等。當多個處理器需要以固定、線性的方式連線時,這可以大大簡化配置。例如,在其他元件之前提供一個轉換器是很常見的。類似地,當你在鏈中某個其他元件之前提供一個過濾器時,你實際上建立了一個 選擇性消費者。在這兩種情況下,鏈只需要一個 input-channel 和一個 output-channel,從而無需為每個單獨的元件定義通道。

MessageHandlerChain 主要為 XML 配置設計。對於 Java DSL,IntegrationFlow 定義可以被視為一個鏈元件,但這與本章下面描述的概念和原理無關。有關更多資訊,請參閱 Java DSL
Spring Integration 的 Filter 提供了一個布林屬性:throwExceptionOnRejection。當你在同一個點對點通道上提供多個具有不同接受標準的“選擇性消費者”時,你應該將此值設定為“true”(預設為 false),這樣排程程式就知道訊息被拒絕了,因此會嘗試將訊息傳遞給其他訂閱者。如果不丟擲異常,排程程式會認為訊息已成功傳遞,即使過濾器已丟棄該訊息以阻止進一步處理。如果你確實想“丟棄”訊息,過濾器的“discard-channel”可能會很有用,因為它確實讓你有機會對丟棄的訊息執行某些操作,例如將其傳送到 JMS 佇列或寫入日誌。

處理器鏈簡化了配置,同時在內部保持了元件之間相同程度的鬆散耦合,並且如果某個時候需要非線性安排,修改配置是微不足道的。

在內部,鏈被擴充套件為列出的端點的線性設定,由匿名通道分隔。鏈內不考慮回覆通道頭。只有在呼叫最後一個處理器後,結果訊息才會被轉發到回覆通道或鏈的輸出通道。由於此設定,除最後一個處理器外,所有處理器都必須實現 MessageProducer 介面(該介面提供 'setOutputChannel()' 方法)。如果在 MessageHandlerChain 上設定了 outputChannel,則最後一個處理器只需要一個輸出通道。

與其他端點一樣,output-channel 是可選的。如果鏈末尾有回覆訊息,則 output-channel 優先。但是,如果它不可用,鏈處理器將檢查入站訊息上的回覆通道頭作為備用。

在大多數情況下,你無需自己實現 MessageHandler。下一節重點介紹鏈元素的名稱空間支援。大多數 Spring Integration 端點,例如服務啟用器和轉換器,都適合在 MessageHandlerChain 中使用。

配置鏈

<chain> 元素提供了一個 input-channel 屬性。如果鏈中的最後一個元素能夠生成回覆訊息(可選),它也支援 output-channel 屬性。子元素可以是過濾器、轉換器、拆分器和服務啟用器。最後一個元素也可以是路由器或出站通道介面卡。以下示例展示了一個鏈定義

<int:chain input-channel="input" output-channel="output">
    <int:filter ref="someSelector" throw-exception-on-rejection="true"/>
    <int:header-enricher>
        <int:header name="thing1" value="thing2"/>
    </int:header-enricher>
    <int:service-activator ref="someService" method="someMethod"/>
</int:chain>

前一個示例中使用的 <header-enricher> 元素將訊息上的訊息頭 thing1 設定為值 thing2。訊息頭豐富器是 Transformer 的一個特化,它只處理訊息頭值。你可以透過實現一個執行訊息頭修改的 MessageHandler 並將其作為 bean 連線來實現相同的效果,但訊息頭豐富器是一個更簡單的選項。

<chain> 可以配置為訊息流的最後一個“封閉式”消費者。對於此解決方案,你可以將一些 <outbound-channel-adapter> 放在 <chain> 的末尾,如下例所示

<int:chain input-channel="input">
    <int-xml:marshalling-transformer marshaller="marshaller" result-type="StringResult" />
    <int:service-activator ref="someService" method="someMethod"/>
    <int:header-enricher>
        <int:header name="thing1" value="thing2"/>
    </int:header-enricher>
    <int:logging-channel-adapter level="INFO" log-full-message="true"/>
</int:chain>
禁止的屬性和元素

不允許在鏈中使用的元件上指定某些屬性,例如 orderinput-channel。輪詢器子元素也是如此。

對於 Spring Integration 核心元件,XML 模式本身強制執行一些這些約束。但是,對於非核心元件或你自己的自定義元件,這些約束由 XML 名稱空間解析器強制執行,而不是由 XML 模式強制執行。

這些 XML 名稱空間解析器約束是在 Spring Integration 2.2 中新增的。如果你嘗試使用不允許的屬性和元素,XML 名稱空間解析器會丟擲 BeanDefinitionParsingException

使用 'id' 屬性

從 Spring Integration 3.0 開始,如果鏈元素具有 id 屬性,則該元素的 bean 名稱是鏈的 id 和元素本身 id 的組合。沒有 id 屬性的元素不註冊為 bean,但每個元素都分配有一個包含鏈 idcomponentName。請考慮以下示例

<int:chain id="somethingChain" input-channel="input">
    <int:service-activator id="somethingService" ref="someService" method="someMethod"/>
    <int:object-to-json-transformer/>
</int:chain>

在前面的例子中

  • <chain> 根元素的 id 為 'somethingChain'。因此,AbstractEndpoint 實現(PollingConsumerEventDrivenConsumer,取決於 input-channel 型別)bean 將此值作為其 bean 名稱。

  • MessageHandlerChain bean 獲取一個 bean 別名(somethingChain.handler),這允許直接從 BeanFactory 訪問此 bean。

  • <service-activator> 不是一個功能齊全的訊息端點(它不是 PollingConsumerEventDrivenConsumer)。它是 <chain> 中的一個 MessageHandler。在這種情況下,在 BeanFactory 中註冊的 bean 名稱是 'somethingChain$child.somethingService.handler'。

  • ServiceActivatingHandlercomponentName 採用相同的值,但沒有 '.handler' 字尾。它變為 'somethingChain$child.somethingService'。

  • 最後一個 <chain> 子元件 <object-to-json-transformer> 沒有 id 屬性。它的 componentName 基於它在 <chain> 中的位置。在這種情況下,它是 'somethingChain$child#1'。(名稱的最後一個元素是鏈中的順序,從 '#0' 開始)。請注意,此轉換器未在應用程式上下文中註冊為 bean,因此它沒有 beanName。但是,它的 componentName 具有一個對日誌記錄和其他目的有用的值。

<chain> 元素的 id 屬性使其符合 JMX 匯出 的條件,並且它們可在 訊息歷史 中進行跟蹤。你可以透過使用適當的 bean 名稱從 BeanFactory 訪問它們,如前所述。

<chain> 元素上提供顯式 id 屬性對於簡化日誌中子元件的識別以及提供從 BeanFactory 等訪問它們非常有用。

在鏈內呼叫鏈

有時,你需要在鏈內對另一個鏈進行巢狀呼叫,然後返回並在原始鏈內繼續執行。為了實現這一點,你可以使用訊息閘道器,方法是包含一個 <gateway> 元素,如下例所示

<int:chain id="main-chain" input-channel="in" output-channel="out">
    <int:header-enricher>
      <int:header name="name" value="Many" />
    </int:header-enricher>
    <int:service-activator>
      <bean class="org.foo.SampleService" />
    </int:service-activator>
    <int:gateway request-channel="inputA"/>
</int:chain>

<int:chain id="nested-chain-a" input-channel="inputA">
    <int:header-enricher>
        <int:header name="name" value="Moe" />
    </int:header-enricher>
    <int:gateway request-channel="inputB"/>
    <int:service-activator>
        <bean class="org.foo.SampleService" />
    </int:service-activator>
</int:chain>

<int:chain id="nested-chain-b" input-channel="inputB">
    <int:header-enricher>
        <int:header name="name" value="Jack" />
    </int:header-enricher>
    <int:service-activator>
        <bean class="org.foo.SampleService" />
    </int:service-activator>
</int:chain>

在前面的示例中,nested-chain-amain-chain 處理結束時由那裡配置的“閘道器”元素呼叫。在 nested-chain-a 中,在訊息頭豐富後呼叫 nested-chain-b。然後流返回到 nested-chain-b 完成執行。最後,流返回到 main-chain。當在鏈中定義 <gateway> 元素的巢狀版本時,它不需要 service-interface 屬性。相反,它接收當前狀態下的訊息並將其放置在 request-channel 屬性中定義的通道上。當由該閘道器啟動的下游流完成後,Message 返回到閘道器並繼續在當前鏈中執行。

© . This site is unofficial and not affiliated with VMware.