消息历史

消息架构的主要优势在于松耦合,参与的组件之间无需相互感知。这一事实本身就使应用程序具有极强的灵活性,您可以更改组件而不会影响其余流程,更改消息路由,更改消息消费样式(轮询与事件驱动)等等。但是,这种看似简单的架构在出现问题时可能会变得难以处理。在调试时,您可能希望尽可能多地获取有关消息的信息(其来源、经过的通道以及其他详细信息)。

消息历史记录正是其中一种有助于提供选项以维护某种程度的消息路径感知的模式,无论出于调试目的还是维护审计跟踪。Spring 集成提供了一种简单的方法来配置消息流以维护消息历史记录,方法是在消息中添加一个标头并在每次消息通过跟踪组件时更新该标头。

消息历史记录配置

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

在应用程序上下文中,必须只声明一个 @EnableMessageHistory(或 <message-history/>)作为组件跟踪配置的唯一来源。请勿对 MessageHistoryConfigurer 使用通用 bean 定义。
在 6.3 版之前,消息历史记录标头是不可变的(您无法重写历史记录):每次创建的跟踪不仅创建了 MessageHistory 的新实例,而且创建了全新的消息副本。现在,它以追加模式工作:第一次跟踪会创建一个带有新 MessageHistory 容器的新消息。所有其余的 MessageHistory.write() 调用都会将新条目添加到现有标头中,并且不会创建新消息。这大大提高了应用程序性能。框架中所有组件(其中相同的消息可以发送到多个使用者(PublishSubscribeChannelAbstractMessageRouterWireTap 等),或者拆分器根据输入消息生成多个输出)现在都将现有的 MessageHistory 标头克隆到这些新消息中。对于框架范围之外的任何其他多生成用例,建议使用 AbstractIntegrationMessageBuilder.cloneMessageHistoryIfAny() API 来确保并行下游子流程贡献其自己的消息历史记录跟踪。