Message History

消息构建体系的主要优点在于松散耦合,以至于参与组件不会维护彼此之间的任何感知。仅这一事实就使应用程序极其灵活,它使你可以更改组件而不影响其余流程、更改消息路由、更改消息消费样式(轮询与事件驱动),等等。但是,当出现问题时,这种不起眼的体系构建样式可能会被证明是困难的。在调试时,或许你需要尽可能多的关于消息的信息(其来源、它已遍历过的通道及其他详细信息)。 消息历史记录是一种模式,它可以通过让你可以选择维护消息路径的某些级别的感知来帮助你,该模式用于调试或维护审计跟踪。Spring 集成提供了一种简单的方法来配置你的消息流程,以通过向消息添加头并每次消息通过跟踪组件时更新头来维护消息历史记录。

Message History Configuration

若要启用消息历史记录,你仅需要在配置中定义 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 作为 JMX MBean 公开(请参见 MBean Exporter),以便在运行时更改模式。但是,请注意,必须停止 bean(关闭消息历史记录)才能更改模式。此功能可能有助于暂时开启历史记录以分析系统。MBean 的对象名称是 <domain>:name=messageHistoryConfigurer,type=MessageHistoryConfigurer

在应用程序上下文中,仅必须声明一个 @EnableMessageHistory(或 <message-history/>)作为组件跟踪配置的单一来源。不要对 MessageHistoryConfigurer 使用通用 Bean 定义。

在版本 6.3 之前,消息历史记录头部是不可变的(你无法重写历史记录):不仅仅是每个创建的轨道的新 MessageHistory 实例,而是完全新的消息副本。现在,它以仅附加模式运行:第一个轨道创建一条带有新 MessageHistory 容器的新消息。所有其他 MessageHistory.write() 调用都会将新条目添加到现有头部,并且没有创建新消息。这极大地提高了应用程序性能。框架中的所有组件,其中同一条消息可以发送到多个消费者(PublishSubscribeChannelAbstractMessageRouterWireTap 等),或者拆分器根据输入消息生成多个输出,现在正在将一个现有 MessageHistory 头部克隆到那些新消息中。对于框架范围外的任何其他多生产用例,推荐使用 AbstractIntegrationMessageBuilder.cloneMessageHistoryIfAny() API 来确保并行下游子流贡献自己的消息历史记录跟踪。