Axon框架深入使用的一点经验

Axon框架(org.axonframework)是一个比较成熟的支持DDD和Event Sourcing编程思想的框架,我比较深入地学习了soooban专家的示例项目(https://github.com/soooban/AxonDemo.git),对该框架有一些自己的认识,同时对原示例项目中的一些问题进行了排查。在此将一些经验进行分享

总体的注意事项

  1. 由于axon有自己的机制,需要通过自动生成DDL语句来创建相应的表,因此建议Axon应用程序也与此相适应,通过指定ddl-auto为update来实现表结构自动更新
  2. 由于axon有自己的机制,项目中不要自己去生成entityManagerFactory,否则会出现各种各样的实体类没有找到的情况(比如遗漏扫描org.axonframework.modelling.saga.repository.jpa包中的实体类),当然可以在调试过程中逐项排查和添加,但笔者没有这么做了

自定义DomainEventEntry

DomainEventEntry是Event写入Repository时使用的实体类,在项目中有较大可能需要进行定制。例如在soooban示例项目中,添加了一个是否已经发送的标志,在我的项目中,增加了是否可以撤销的标志和其他一些信息。注意事项如下:

1、项目应当添加继承自某个DomainEventyEntry的实体类,该实体类的名称必须等于“DomainEventEntry”,例如添加@Entity(name = "DomainEventEntry")这样的注解;

2、项目不能再扫描org.axonframework.eventsourcing.eventstore.jpa包中的实体类,否则会出现重复绑定的错误,soooban示例项目中有一段这样的注解,应当注释掉:

@RegisterDefaultEntities(packages = {
    "org.axonframework.eventsourcing.eventstore.jpa"
})

3、但是Event Store依赖于继承自DomainEventEntry和SnapshotEventEntry的实体类,因此我们可以定义一个什么也不改变的CustomSnapshotEventEntry,继承自SnapshotEventEntry,在自定义的CustomJpaEventStorageEngine中,重载基类JpaEventStorageEngine的createSnapshotEntity方法,在该方法中创建CustomSnapshotEventEntry(JpaEventStorageEngine中设计createEventEntity和createSnapshotEntity这两个方法,其目的就是给应用程序来重载的),当然我们也可以不进行重载,直接通过orm.xml文件来指定,如下所示:

 

<entity class="org.axonframework.eventsourcing.eventstore.jpa.SnapshotEventEntry" access="FIELD">
    <attributes>
        <id name="aggregateIdentifier">
            <column name="aggregateIdentifier"/>
        </id>
        <id name="sequenceNumber">
            <column name="sequenceNumber"/>
        </id>
        <id name="type">
            <column name="type"/>
        </id>
    </attributes>
</entity>

 

Upcast的问题——Aggregate类也需要纳入版本管理

由于应用程序会进行更新,在更新前后Event的数据结构会有所不一样,因此Axon定义了Upcast过程,将较早版本的Event转换成最新版本的Event。soooban示例程序演示Upcast过程,但是其实现的逻辑比较简单,并且忽略了一个细节,导致发生如下错误:

不停地更改Aggregate,会产生Snapshot,但是产生Snapshot后,查询Aggregate的值,发现某个字段的值并不是所期望的值,
而是Upcaster中的一个默认值。

其原因是

1、项目使用AnnotationRevisionResolver来判断每个Event的版本,这个RevisionResolver会检查每个Event类中是否
有@Revision注解,并取其值作为版本;
2、项目对Event基类添加了@Revision注解,但是未对Aggregate类添加@Revision注解
3、在DomainEventData还原成DomainEventMessage过程中(参见EventStreamUtils#upcastAndDeserializeDomainEvents),
对于SnapshotEvent,其Payload并不是Event,而是Aggregate
4、项目的Upcaster的逻辑比较简单,只要Event没有版本号,就将某个新增字段设为默认值
5、因此在读取Snapshot并还原成EventMessage时,由于没有版本号,因此执行了Upcast过程

通过在Aggregate类中添加@Revision注解,解决此问题

其他可能的错误

如果出现了Sequence "HIBERNATE_SEQUENCE" not found的错误,其原因是使用Mysql数据库时,其顺序号生成器的策略应当设成IDENTITY,可以在orm.xml中如下设置:

<mapped-superclass class="org.axonframework.eventhandling.AbstractSequencedDomainEventEntry" access="FIELD">
    <attributes>
        <id name="globalIndex">
            <generated-value strategy="IDENTITY"/>
        </id>
    </attributes>
</mapped-superclass>

<entity class="org.axonframework.modelling.saga.repository.jpa.AssociationValueEntry" access="FIELD">
    <attributes>
        <id name="id">
            <generated-value strategy="IDENTITY"/>
        </id>
    </attributes>
</entity>

后记

我继承soooban的示例项目,在进行练手,比如增加一个Rollback的功能。

对于Event Sourcing的应用程序而言,本是不存在回退的功能的,因为Event的作用就是原原本本地记录所发生过的一切,但是
我们可以通过读取一个指定“截至Sequence Number”的Event Stream来还原某一个时点的Aggregate,然后发起一个Update的
Command更改其状态,这样模拟进行Rollback

项目地址:

https://e.coding.net/sharework/axon-advanced-starter.git

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值