23.Axon框架-事件(一)

175 阅读3分钟

Axon框架-事件(一)

1.什么是事件

1768022347510.png

2.发布事件

介绍

1768029536411.png

在聚合内部发布事件

介绍

1768029556004.png

代码

AggregateLifecycle提供了简洁的API来实现上述需求,核心方法为静态的apply(),使用时需静态导入:

import static org.axonframework.modelling.command.AggregateLifecycle.apply;

public class GiftCard {

    @AggregateIdentifier
    private String id;
    private int balance;

    // 命令处理器:处理“发行礼品卡”命令
    @CommandHandler
    public GiftCard(IssueCardCommand cmd) {
        // 发布“礼品卡已发行”事件,事件数据来自命令
        apply(new CardIssuedEvent(cmd.getCardId(), cmd.getAmount()));
    }

    // 事件溯源处理器:通过事件重建聚合状态(示例)
    @EventSourcingHandler
    public void on(CardIssuedEvent event) {
        this.id = event.getCardId();
        this.balance = event.getAmount();
    }

    // 省略其他命令处理器、事件处理器及状态字段
}
apply方法内部机制

1768029841169.png

apply高级技巧

1768029911027.png

@CommandHandler
public void handle(RedeemCardCommand cmd) {
    if (this.balance < cmd.getRedeemAmount()) {
        throw new InsufficientBalanceException(id, balance, cmd.getRedeemAmount());
    }
    // 1. 发布“礼品卡已兑换”事件,并附加元数据(兑换门店ID)
    apply(
        new CardRedeemedEvent(id, cmd.getRedeemAmount()),
        MetaData.with("shopId", cmd.getShopId()) // 元数据:门店ID
    )
    // 2. 事件发布后,执行后续逻辑(如记录兑换日志)
    .andThen(() -> log.info("Card {} redeemed at shop {}", id, cmd.getShopId()))
    // 3. 若余额为0,发布“礼品卡已失效”事件
    .andThenApplyIf(
        () -> this.balance == 0, // 条件:余额为0
        () -> new CardExpiredEvent(id) // 满足条件时发布的事件
    );
}

// 事件溯源处理器:处理 CardRedeemedEvent 以更新余额
@EventSourcingHandler
public void on(CardRedeemedEvent event) {
    this.balance -= event.getRedeemAmount();
}

从非聚合组件中分发事件

介绍

1768031456575.png

代码
import org.axonframework.eventhandling.gateway.EventGateway;
import org.springframework.stereotype.Service;

@Service // 常规 Spring 服务组件(非聚合)
public class GiftCardNotificationService {

    // 注入 EventGateway(Axon 自动配置,或手动配置)
    private final EventGateway eventGateway;

    // 构造函数注入
    public GiftCardNotificationService(EventGateway eventGateway) {
        this.eventGateway = eventGateway;
    }

    // 发布“礼品卡兑换通知”事件(非聚合发起)
    public void sendRedeemNotification(String cardId, int amount, String userId) {
        // 直接通过 EventGateway 发布事件
        eventGateway.publish(
            new CardRedeemNotifiedEvent(cardId, amount, userId, System.currentTimeMillis())
        );
    }
}
注意
  1. 非聚合组件发布的事件不会自动附加聚合标识符和序号(因不属于任何聚合),若需关联聚合信息,需手动在事件负载或元数据中添加
  2. EventGateway的publish()方法默认是异步的,若需同步等待事件发布结果,可使用publishAndWait()方法

3.处理事件

介绍

1768031538254.png

1768031579655.png

参数

第一个参数,它对应事件消息的负载。若事件处理器无需直接访问消息负载,也可在@EventHandler注解上显式指定预期的负载类型

注意:若希望将负载作为参数传入方法,则不要在@EventHandler注解上配置负载类型

匹配规则

1768031651672.png

注册

介绍

事件处理组件需通过EventProcessingConfigurer进行注册,该配置器可从全局的Axon Configurer中获取

  • 通常一个应用只需定义一个EventProcessingConfiguration
  • 对于大型、模块化的应用,也可为每个模块单独定义一个EventProcessingConfiguration
原生API
public class AxonConfig {
    // 省略其他配置方法...
    public void configureEventHandler(Configurer configurer) {
        // 方式1:直接注册事件处理组件(仅处理 @EventHandler 方法)
        configurer.registerEventHandler(
                config -> new MyEventHandlingComponent()
        );

        // 方式2:注册包含多种消息处理器的组件(如同时有 @EventHandler、@CommandHandler)
        configurer.registerMessageHandler(
                config -> new MyEventHandlingComponent()
        );

        // 方式3:通过 EventProcessingConfigurer 直接注册(更显式的事件处理配置)
        configurer.eventProcessing()
            .registerEventHandler(config ->
                new MyEventHandlingComponent()
            );
    }
}
SpringBoot
@Component // 纳入 Spring 上下文,Axon 会自动扫描 @EventHandler 方法
public class MyEventHandlingComponent {

    @EventHandler
    public void on(SomeEvent event) {
        // 处理 SomeEvent 事件的业务逻辑
        // 示例:更新查询模型、发送通知、触发后续命令等
    }

    // 可添加更多 @EventHandler 方法处理其他事件
    @EventHandler
    public void on(AnotherEvent event) {
        // 处理 AnotherEvent 事件
    }
}

4.总结当前的事件生命周期

1768032013124.png