消息历史
消息传递架构的主要好处是松耦合,使得参与的组件彼此之间没有任何认知。这一事实本身使应用程序具有极大的灵活性,让您可以在不影响其余流程的情况下更改组件,更改消息传递路由,更改消息消费方式(轮询与事件驱动),等等。然而,这种看似简单的架构风格在出现问题时可能会变得难以处理。在调试时,您可能希望获取有关消息的尽可能多的信息(其来源、它所经过的通道以及其他详细信息)。
消息历史是一种模式,通过提供选项来保持对消息路径一定程度的了解,无论是出于调试目的还是为了维护审计跟踪。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/>
)作为组件跟踪配置的单一来源。不要使用通用的bean定义来定义 MessageHistoryConfigurer
。
在 6.3 版本之前,消息历史记录头部是不可变的(你不能重写历史):每一个新创建的 track 不仅创建了 MessageHistory
的新实例,还创建了全新的消息副本。现在它以追加模式工作:第一个 track 创建带有新 MessageHistory
容器的新消息。其余所有的 MessageHistory.write()
调用都会向现有头部添加新条目——而不会创建新的消息。这显著提高了应用程序的性能。框架中所有可以将相同的消息发送给多个消费者的组件(如 PublishSubscribeChannel
、AbstractMessageRouter
、WireTap
等),或者根据输入消息生成多个输出的拆分器,现在都会将现有的 MessageHistory
头部克隆到这些新消息中。对于任何其他多生产者使用场景,如果超出了框架的范围,建议使用 AbstractIntegrationMessageBuilder.cloneMessageHistoryIfAny()
API 来确保并行的下游子流能够贡献它们自己的消息历史记录痕迹。