訊息歷史

訊息傳遞架構的主要優勢是鬆散耦合,因此參與元件之間不會維持任何彼此的感知。僅此一項事實就使應用程式極其靈活,讓您可以變更元件而不會影響流程的其餘部分、變更訊息路由、變更訊息消耗樣式(輪詢與事件驅動)等等。但是,當出現問題時,這種樸實無華的架構可能會被證明是困難的。在偵錯時,您可能希望獲得關於訊息的盡可能多的資訊(其來源、它所遍歷的通道和其他詳細資訊)。

訊息歷史是其中一種模式,透過讓您選擇維護訊息路徑的某種程度的感知,無論是為了偵錯目的還是為了維護稽核追蹤,它都有所幫助。Spring Integration 提供了一種簡單的方式來設定您的訊息流程,以透過將標頭新增至訊息並在訊息每次通過追蹤元件時更新該標頭來維護訊息歷史。

訊息歷史設定

若要啟用訊息歷史,您只需要在您的設定中定義 message-history 元素(或 @EnableMessageHistory),如下列範例所示

  • Java

  • XML

@Configuration
@EnableIntegration
@EnableMessageHistory
<int:message-history/>

現在,每個具名的元件(已定義 'id')都會被追蹤。框架會在您的訊息中設定 'history' 標頭。其值為 List<Properties>

考慮下列設定範例

  • Java

  • XML

@MessagingGateway(defaultRequestChannel = "bridgeInChannel")
public interface SampleGateway {
   ...
}

@Bean
@Transformer(inputChannel = "enricherChannel", outputChannel="filterChannel")
HeaderEnricher sampleEnricher() {
    HeaderEnricher enricher =
           new HeaderEnricher(Collections.singletonMap("baz", new StaticHeaderValueMessageProcessor("baz")));
    return enricher;
}
<int:gateway id="sampleGateway"
    service-interface="org.springframework.integration.history.sample.SampleGateway"
    default-request-channel="bridgeInChannel"/>

<int:header-enricher id="sampleEnricher" input-channel="enricherChannel" output-channel="filterChannel">
    <int:header name="baz" value="baz"/>
</int:header-enricher>

先前的設定產生了一個簡單的訊息歷史結構,其輸出類似於以下內容

[{name=sampleGateway, type=gateway, timestamp=1283281668091},
 {name=sampleEnricher, type=header-enricher, timestamp=1283281668094}]

若要存取訊息歷史,您只需要存取 MessageHistory 標頭。下列範例顯示如何執行此操作

Iterator<Properties> historyIterator =
    message.getHeaders().get(MessageHistory.HEADER_NAME, MessageHistory.class).iterator();
assertTrue(historyIterator.hasNext());
Properties gatewayHistory = historyIterator.next();
assertEquals("sampleGateway", gatewayHistory.get("name"));
assertTrue(historyIterator.hasNext());
Properties chainHistory = historyIterator.next();
assertEquals("sampleChain", chainHistory.get("name"));

您可能不想追蹤所有元件。若要將歷史記錄限制為基於其名稱的特定元件,您可以提供 tracked-components 屬性,並指定以逗號分隔的元件名稱和模式清單,以比對您要追蹤的元件。下列範例顯示如何執行此操作

  • Java

  • XML

@Configuration
@EnableIntegration
@EnableMessageHistory("*Gateway", "sample*", "aName")
<int:message-history tracked-components="*Gateway, sample*, aName"/>

在先前的範例中,僅針對以 'Gateway' 結尾、以 'sample' 開頭或與名稱 'aName' 完全相符的元件維護訊息歷史。

此外,MessageHistoryConfigurer bean 現在透過 IntegrationMBeanExporter (請參閱 MBean Exporter) 作為 JMX MBean 公開,讓您可以在執行階段變更模式。但是請注意,必須停止 bean(關閉訊息歷史記錄)才能變更模式。此功能可能對於暫時開啟歷史記錄以分析系統很有用。MBean 的物件名稱為 <domain>:name=messageHistoryConfigurer,type=MessageHistoryConfigurer

應用程式內容中必須只宣告一個 @EnableMessageHistory(或 <message-history/>)作為元件追蹤設定的單一來源。請勿對 MessageHistoryConfigurer 使用通用 bean 定義。
在 6.3 版之前,訊息歷史記錄標頭是不可變的(您無法重新寫入歷史記錄):每次建立的單個軌跡不僅會建立 MessageHistory 的新實例,而且還會建立全新的訊息副本。現在它以僅附加模式運作:第一個軌跡會建立一個新訊息,其中包含新的 MessageHistory 容器。所有剩餘的 MessageHistory.write() 呼叫都會將新條目新增至現有的標頭 - 並且不會建立新訊息。這顯著提高了應用程式效能。框架中的所有元件,其中相同的訊息可以傳送給多個消費者(PublishSubscribeChannelAbstractMessageRouterWireTap 等),或者分割器會根據輸入訊息產生多個輸出,現在都會將現有的 MessageHistory 標頭複製到這些新訊息中。對於框架範圍之外的任何其他多生產用例,建議使用 AbstractIntegrationMessageBuilder.cloneMessageHistoryIfAny() API,以確保並行下游子流程貢獻其自己的訊息歷史追蹤。