消息历史
消息架构的主要优点是松散耦合,参与组件彼此之间没有任何感知。这一事实本身就使得应用程序极其灵活,允许您更改组件而不影响流程的其余部分、更改消息路由、更改消息消费方式(轮询与事件驱动)等等。然而,当出现问题时,这种朴素的架构风格可能难以调试。在调试时,您可能希望尽可能多地获取关于消息的信息(其来源、它经过的通道以及其他详细信息)。
消息历史是帮助实现这一目标的模式之一,它提供了一个选项,让您可以维护消息路径的某些层面的感知,无论是用于调试目的还是用于维护审计跟踪。Spring Integration 提供了一种简单的方法来配置您的消息流以维护消息历史,方法是向消息添加一个头,并在消息每次通过被跟踪的组件时更新该头。
消息历史配置
要启用消息历史,您只需在配置中定义 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(参见 MBean 导出器)作为 JMX MBean 公开,允许您在运行时更改模式。但是请注意,必须停止 bean(关闭消息历史)才能更改模式。此功能可能有助于暂时打开历史以分析系统。MBean 的对象名称是 <domain>:name=messageHistoryConfigurer,type=MessageHistoryConfigurer。
在应用程序上下文中,必须只声明一个 @EnableMessageHistory(或 <message-history/>),作为组件跟踪配置的单一来源。不要为 MessageHistoryConfigurer 使用通用 bean 定义。 |
在 6.3 版本之前,消息历史头是不可变的(您无法重写历史):每次跟踪不仅会创建 MessageHistory 的新实例,还会创建一个全新的消息副本。现在它以追加模式工作:第一次跟踪会创建一个新消息,其中包含新的 MessageHistory 容器。所有其余的 MessageHistory.write() 调用都会向现有头添加新条目,并且不会创建新消息。这显著提高了应用程序性能。框架中的所有组件,其中相同的消息可以发送给多个消费者(PublishSubscribeChannel、AbstractMessageRouter、WireTap 等),或者拆分器根据输入消息生成多个输出,现在都将现有的 MessageHistory 头克隆到这些新消息中。对于框架范围之外的任何其他多生产者用例,建议使用 AbstractIntegrationMessageBuilder.cloneMessageHistoryIfAny() API,以确保并行下游子流贡献自己的消息历史跟踪。 |