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