メッセージ履歴

メッセージングアーキテクチャの主な利点は、参加しているコンポーネントが相互の認識を維持できないように、疎結合です。この事実だけで、アプリケーションは非常に柔軟になり、残りのフローに影響を与えずにコンポーネントを変更したり、メッセージングルートを変更したり、メッセージ消費スタイルを変更したりできます(ポーリングとイベントドリブン)。しかし、この控えめなスタイルのアーキテクチャは、物事がうまくいかない場合には難しいことがわかります。デバッグするときは、おそらくメッセージに関する情報(その発信元、通過したチャネル、その他の詳細)をできるだけ多く取得する必要があります。

メッセージ履歴は、デバッグまたは監査証跡を維持するために、メッセージパスの認識レベルを維持するオプションを提供することで役立つパターンの 1 つです。Spring 統合は、メッセージにヘッダーを追加し、メッセージが追跡対象コンポーネントを通過するたびにそのヘッダーを更新することにより、メッセージフローを設定してメッセージ履歴を維持する簡単な方法を提供します。

メッセージ履歴の構成

メッセージ履歴を有効にするには、次の例に示すように、構成で message-history 要素 (または @EnableMessageHistory) を定義するだけで済みます。

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

これで、すべての名前付きコンポーネント( "id" が定義されているコンポーネント)が追跡されます。フレームワークは、メッセージに "history" ヘッダーを設定します。その値は List<Properties> です。

次の構成例を検討してください。

@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 属性を指定し、追跡するコンポーネントに一致するコンポーネント名とパターンのコンマ区切りリストを指定できます。次の例は、その方法を示しています。

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

前の例では、'Gateway' で終わる、'sample' で始まる、または名前 'aName' と完全に一致するコンポーネントに対してのみ、メッセージ履歴が保持されます。

さらに、MessageHistoryConfigurer Bean が IntegrationMBeanExporter によって JMX MBean として公開され ( MBean エクスポーターを参照)、実行時にパターンを変更できるようになりました。ただし、パターンを変更するには、Bean を停止 (メッセージ履歴をオフにする) する必要があることに注意してください。この機能は、システムを分析するために履歴を一時的にオンにするのに役立つ場合があります。MBean のオブジェクト名は <domain>:name=messageHistoryConfigurer,type=MessageHistoryConfigurer です。

1 つの @EnableMessageHistory (または <message-history/>) のみを、コンポーネント追跡構成の単一ソースとしてアプリケーションコンテキストで宣言する必要があります。MessageHistoryConfigurer に汎用 Bean 定義を使用しないでください。
定義により、メッセージ履歴ヘッダーは不変です(履歴を書き換えることはできません)。メッセージ履歴値を書き込むとき、コンポーネントは新しいメッセージを作成するか(コンポーネントがオリジンの場合)、リクエストメッセージから履歴をコピーし、それを変更して応答メッセージに新しいリストを設定します。どちらの場合でも、メッセージ自体がスレッドの境界を越えている場合でも、値を追加できます。つまり、履歴値により、非同期メッセージフローのデバッグが大幅に簡素化されます。