消息
1.介绍
在Axon中,组件之间的所有通信都是通过Message接口的对象表示的显式消息完成的
Axon中的核心概念之一是消息传递。组件之间的所有通信都通过消息对象完成。这为这些组件提供了必要的位置透明性,以便在需要时能够扩展和分布这些组件
2.类型
- 命令(CommandMessage):用于描述变更应用状态的意图
- 事件(EventMessage):是用于描述应用中已发生事情的对象
- 查询(QueryMessage):用于描述获取信息或状态的请求
3.组成
- 负载(payload):消息的内容(如命令、事件的具体内容)
- 元数据(metadata):以键值对(String→Object)形式存在,描述消息发送的上下文,如跟踪信息、安全上下文等,典型用途为审计、日志记录,不应基于元数据做业务决策
- 唯一标识符(unique identifier):唯一ID,用于标识消息
4.流转过程
- Command被发送至CommandBus
- CommandBus将命令分发给对应的CommandHandler
- CommandHandler会应用事件,这些事件随后会被发布
- 已发布的事件由EventHandler接收并处理,EventHandler可用于更新读模型
- 后续可通过发送QueryMessage,查询已更新的读模型以获取所需信息
5.不可变特性
消息是不可变的。这意味着,若要添加新元素,实际上需要创建一个新的消息实例。为了能将两个Java对象实例视为代表同一个概念性消息,每个消息都有一个标识符。修改消息的元数据不会改变这个标识符
6.元数据
介绍
以键值对(String→Object)形式存在,描述消息发送的上下文,如跟踪信息、安全上下文等,典型用途为审计、日志记录,不应基于元数据做业务决策
创建
java
MetaData metaData = MetaData.with("myKey", 42)
.and("otherKey", "some value");
消息中的元数据
java
EventMessage eventMessage = GenericEventMessage
.asEventMessage("myPayload")
.withMetaData(Collections.singletonMap("myKey", 42))
.andMetaData(Collections.singletonMap("otherKey", "some value"));
- 创建一个以"myPayload"作为有效载荷的EventMessage
- withMetaData将消息中的所有元数据替换为给定的Map。在本例中,java.util.Collections.singletonMap()用于定义单个条目
- andMetaData将给定Map中的条目添加到消息的元数据中。具有相同键的现有条目将被覆盖
不可变特性
与常规的不同Map<String,Object>,MetaData在Axon中的是不可变的。状态变更的方法将创建并返回一个新实例,而不是修改现有实例
由于MetaData是不可变的, 的所有变异操作Map都会抛出UnsupportedOperationException
7.消息关联
介绍
在消息传递系统中,将消息分组或关联是常见做法。在Axon Framework中,一个Command消息可能产生一个或多个Event消息,一个Query消息可能产生一个或多个QueryResponse消息。通常,关联通过特定的消息属性(即所谓的关联标识符,correlation identifier)来实现
CorrelationDataProvider
Axon Framework中的消息使用MetaData属性来传输消息的元信息。MetaData对象的类型为Map<String, Object>,会随消息一起传递。要填充在一个工作单元(Unit of Work)中生成的新消息的MetaData,可以使用所谓的CorrelationDataProvider。工作单元负责基于此CorrelationDataProvider填充新消息的MetaData
接口定义如下:
java
@FunctionalInterface
public interface CorrelationDataProvider {
Map<String, ?> correlationDataFor(Message<?> message);
}
常见实现如下:

MessageOriginProvider
介绍
MessageOriginProvider是默认的。它负责在消息之间传递两个值:correlationId和traceId
基本概念
- correlationId:指向父消息的id
- traceId:指向消息链的根消息id
当创建新消息时,如果父消息中不存在这两个字段,将使用新消息自身的标识符同时作为这两个值
案例理解
举个例子,如果你处理一个Command消息,而该Command消息又发布了一个Event消息,那么Event消息的MetaData将基于以下内容填充:
- Command消息的id作为correlationId
- Command消息的MetaData中若存在traceId,则使用该值;否则,使用Command消息的id作为traceId
SimpleCorrelationDataProvider
介绍
SimpleCorrelationDataProvider是无条件地将指定key的值从一个消息复制到另一个消息的元数据中。要实现这一点,必须调用SimpleCorrelationDataProvider的构造函数,并传入应被复制的key的列表
代码
java
public class Configuration {
public CorrelationDataProvider customCorrelationDataProvider() {
return new SimpleCorrelationDataProvider("myId", "myId2");
}
}
MultiCorrelationDataProvider
介绍
MultiCorrelationDataProvider能够组合多个CorrelationDataProvider的效果。要实现这一点,必须调用MultiCorrelationDataProvider的构造函数,并传入一个提供器列表
代码
java
public class Configuration {
public CorrelationDataProvider customCorrelationDataProviders() {
return new MultiCorrelationDataProvider<CommandMessage<?>>(
Arrays.asList(
new SimpleCorrelationDataProvider("someKey"),
new MessageOriginProvider()
)
);
}
}
自定义
介绍
如果预定义的提供器不能满足你的需求,你始终可以实现自己的CorrelationDataProvider。该类必须实现CorrelationDataProvider接口
使用步骤
- 定义一个类实现CorrelationDataProvider接口
- 在配置中注册
实现
java
public class AuthCorrelationDataProvider implements CorrelationDataProvider {
private final Function<String, String> usernameProvider;
public AuthCorrelationDataProvider(Function<String, String> userProvider) {
this.usernameProvider = userProvider;
}
@Override
public Map<String, ?> correlationDataFor(Message<?> message) {
Map<String, Object> correlationData = new HashMap<>();
if (message instanceof CommandMessage<?>) {
if (message.getMetaData().containsKey("authorization")) {
String token = (String) message.getMetaData().get("authorization");
correlationData.put("username", usernameProvider.apply(token));
}
}
return correlationData;
}
}
在配置中注册
原生API注册代码:
java
public class Configuration {
public void configuring() {
Configurer configurer = DefaultConfigurer
.defaultConfiguration()
.configureCorrelationDataProviders(config -> Arrays.asList(
new SimpleCorrelationDataProvider("someKey"),
new MessageOriginProvider()
));
}
}
SpringBoot注册代码:
java
@Configuration
public class CorrelationDataProviderConfiguration {
// 配置单个 CorrelationDataProvider 会自动覆盖默认的 MessageOriginProvider
@Bean
public CorrelationDataProvider someKeyCorrelationProvider() {
return new SimpleCorrelationDataProvider("someKey");
}
@Bean
public CorrelationDataProvider messageOriginProvider() {
return new MessageOriginProvider();
}
}