Axon框架(org.axonframework)是一个比较成熟的支持DDD和Event Sourcing编程思想的框架,我比较深入地学习了soooban专家的示例项目(https://github.com/soooban/AxonDemo.git),对该框架有一些自己的认识,同时对原示例项目中的一些问题进行了排查。在此将一些经验进行分享
总体的注意事项
- 由于axon有自己的机制,需要通过自动生成DDL语句来创建相应的表,因此建议Axon应用程序也与此相适应,通过指定ddl-auto为update来实现表结构自动更新
- 由于axon有自己的机制,项目中不要自己去生成entityManagerFactory,否则会出现各种各样的实体类没有找到的情况(比如遗漏扫描org.axonframework.modelling.saga.repository.jpa包中的实体类),当然可以在调试过程中逐项排查和添加,但笔者没有这么做了
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
推荐阅读
- AXON|(第8天)每日源码调试之旅--实现CQRS模式的AXON框架
- (译)使用Spring Boot和Axon实现CQRS&Event Sourcing
- Axon框架指南 - Baeldung
- Java开发|js 解决Safari浏览器中实现支付宝网页支付无法拉取支付宝APP的问题
- JAVA开发|java调用go、js、python、groovy和Caffeine缓存