如需使用最新稳定版本,请使用 Spring Integration 7.0.4spring-doc.cadn.net.cn

消息历史

消息架构的关键优势在于松耦合,使得参与组件之间无需相互感知。 仅凭这一点,就能使应用程序极具灵活性,允许您更改组件而不影响其余流程、更改消息路由、更改消息消费方式(轮询与事件驱动)等。 然而,当出现问题时,这种低调的架构风格可能会带来困难。 在调试时,您可能希望尽可能获取关于消息的更多信息(包括其来源、经过的通道以及其他细节)。spring-doc.cadn.net.cn

消息历史是那些通过提供选项来维护对消息路径的某种程度的感知,以便用于调试目的或维护审计跟踪的模式之一。 Spring Integration 提供了一种简单的方法来配置您的消息流,通过在消息中添加一个标头并在每次消息通过受跟踪组件时更新该标头来维护消息历史。spring-doc.cadn.net.cn

消息历史配置

要启用消息历史记录,您只需在配置中定义 message-history 元素(或 @EnableMessageHistory),如下例所示:spring-doc.cadn.net.cn

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

现在,每个已命名的组件(即定义了'id'的组件)都会被追踪。 框架会在您的消息中设置'history'标头。 其值为 List<Properties>spring-doc.cadn.net.cn

考虑以下配置示例:spring-doc.cadn.net.cn

@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>

上述配置生成了一个简单的消息历史结构,输出类似于以下内容:spring-doc.cadn.net.cn

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

要访问消息历史,您只需访问 MessageHistory 标头。 以下示例展示了如何实现:spring-doc.cadn.net.cn

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 属性,并指定一个逗号分隔的组件名称和模式列表,以匹配您希望跟踪的组件。 以下示例展示了如何实现:spring-doc.cadn.net.cn

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

在前面的示例中,消息历史仅针对以'Gateway'结尾、以'sample'开头或完全匹配名称'aName'的组件进行维护。spring-doc.cadn.net.cn

此外,MessageHistoryConfigurer Bean 现在由 IntegrationMBeanExporter 作为 JMX MBean 公开(参见 MBean 导出器),允许您在运行时更改模式。 但请注意,必须停止该 Bean(关闭消息历史)才能更改模式。 此功能可能有助于临时开启历史记录以分析系统。 MBean 的对象名称为 <domain>:name=messageHistoryConfigurer,type=MessageHistoryConfigurerspring-doc.cadn.net.cn

在应用上下文中,必须仅声明一个 @EnableMessageHistory(或 <message-history/>)作为组件跟踪配置的唯一来源。 不要为 MessageHistoryConfigurer 使用通用的 Bean 定义。
在 6.3 版本之前,消息历史头是不可变的(您无法重写历史):每个创建的跟踪不仅会生成一个新的 MessageHistory 实例,还会生成一条完整的新消息副本。 现在它以追加模式运行:第一个跟踪会创建一个带有新 MessageHistory 容器且包含新消息的对象。 所有其余的 MessageHistory.write() 调用都会向现有头添加新条目,而不会创建新消息。 这显著提升了应用程序的性能。 框架中所有允许将同一条消息发送给多个消费者(PublishSubscribeChannelAbstractMessageRouterWireTap 等)的场景,或者拆分器根据输入消息产生多个输出结果的组件,现在都会将现有的 MessageHistory 头克隆到这些新消息中。 对于框架范围之外的任何其他多生产者用例,建议使用 AbstractIntegrationMessageBuilder.cloneMessageHistoryIfAny() API,以确保并行的下游子流能够贡献它们各自的消息历史跟踪。