java开发|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")这样的注解;
【java开发|Axon框架深入使用的一点经验】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文件来指定,如下所示:



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中如下设置:

后记 我继承soooban的示例项目,在进行练手,比如增加一个Rollback的功能。
对于Event Sourcing的应用程序而言,本是不存在回退的功能的,因为Event的作用就是原原本本地记录所发生过的一切,但是
我们可以通过读取一个指定“截至Sequence Number”的Event Stream来还原某一个时点的Aggregate,然后发起一个Update的
Command更改其状态,这样模拟进行Rollback
项目地址:
https://e.coding.net/sharework/axon-advanced-starter.git

    推荐阅读