AxonFramework 命令处理器(Command Handlers)深度解析
命令处理器概述
在AxonFramework中,命令处理器(Command Handlers)是CQRS架构中处理命令的核心组件。它们负责接收命令消息(Command Messages),执行业务逻辑,并产生相应的事件(Events)。命令处理器可以放置在聚合根(Aggregate)内部,也可以作为独立的外部组件存在。
聚合根内的命令处理器
基本用法
在聚合根中定义命令处理器是最推荐的方式,因为聚合根包含了处理命令所需的状态。通过在方法上添加@CommandHandler
注解即可将其标记为命令处理器:
@CommandHandler
public void handle(RedeemCardCommand cmd) {
// 处理逻辑
}
默认情况下,处理器会匹配第一个参数类型的完全限定类名作为命令名称。也可以通过注解显式指定命令名称:
@CommandHandler(commandName = "customCommandName")
目标聚合标识
为了让Axon知道哪个聚合实例应该处理命令,命令对象中必须使用@TargetAggregateIdentifier
标注聚合标识字段:
public class RedeemCardCommand {
@TargetAggregateIdentifier
private final String cardId;
// 其他字段...
}
创建聚合的命令处理器
当@CommandHandler
注解放在聚合的构造函数上时,该命令将创建一个新的聚合实例:
@CommandHandler
public GiftCard(IssueCardCommand cmd) {
apply(new CardIssuedEvent(cmd.getCardId(), cmd.getAmount()));
}
创建命令不需要@TargetAggregateIdentifier
注解,因为此时聚合还不存在。
业务逻辑与状态变更
在命令处理器中应遵循以下原则:
- 只做决策:检查聚合是否处于正确状态来决定是否处理命令
- 不直接修改状态:状态变更应通过事件溯源处理器(Event Sourcing Handlers)完成
- 必要时抛出异常:当业务规则被违反时抛出异常
创建策略
Axon提供了@CreationPolicy
注解来定义命令处理器的创建行为:
@CommandHandler
@CreationPolicy(AggregateCreationPolicy.ALWAYS)
public void handle(IssueCardCommand cmd) {
// 总是创建新聚合
}
@CommandHandler
@CreationPolicy(AggregateCreationPolicy.CREATE_IF_MISSING)
public void handle(CreateOrRechargeCardCommand cmd) {
// 如果不存在则创建,否则更新
}
可用策略包括:
ALWAYS
:总是创建新聚合CREATE_IF_MISSING
:不存在时创建(upsert模式)NEVER
:只处理现有聚合
外部命令处理器
虽然推荐将命令处理器放在聚合内部,但有时需要将处理器放在普通对象中:
public class GiftCardCommandHandler {
private final Repository<GiftCard> giftCardRepository;
@CommandHandler
public void handle(RedeemCardCommand cmd) {
giftCardRepository.load(cmd.getCardId())
.execute(giftCard -> giftCard.handle(cmd));
}
}
外部命令处理器特点:
- 是单例对象,处理所有匹配的命令
- 需要手动加载聚合并执行操作
- 通过
Repository
和execute
方法确保正确的聚合生命周期
最佳实践
- 保持聚合精简:只包含必要的状态来做决策
- 明确创建策略:清楚地定义每个命令处理器的创建行为
- 合理使用外部处理器:当逻辑不适合放在聚合内时使用
- 充分测试:确保命令处理器和事件溯源处理器正确协作
- 考虑分布式环境:使用
@RoutingKey
确保命令能正确路由
通过合理使用AxonFramework的命令处理器,可以构建出清晰、可维护的CQRS架构应用,实现业务逻辑与基础设施的良好分离。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考