本文关键字:
领域驱动设计(DDD, Domain Driven Design)、微服务(Microservices)、JVM、Spring Boot、Spring、Java、Reactive(响应式编程)、Service Mesh、Cloud Native、后端服务、Java后端服务、Java微服务、Java架构设计、Java项目实战、后端项目实战
DDD(Domain Driven Design, 领域驱动设计)实战系列之CQRS篇. 本文将从电商应用层面, 剖析CQRS该如何设计, 并顺便介绍一种轻量级的CQRS框架—Axon.
想了解更多DDD(领域驱动设计)相关知识、提升DDD实战技能, 请点击这里
Axon 简介
Axon有助于开发更加模块化的SOA服务, Axon框架本身也提供Aggregates(聚合子)、Repostories及Event Bus(事件总线)等实现. Axon支持Java注解(annotation), 开发友好, 如在构建Aggregates或事件监听器时更加容易上手. 运行Axon本身并不会创建其它线程(或连接), 可以安全地运行在Web应用服务器上(如Tomcat,Jetty等), Axon底层主要通过Executor封装异步行为, 解耦各项Task.
代码实战
以电商场景为例, 如下, 业务领域(Domain)主要有俩大实体: 订单和产品. 用户购买产品、创建新订单, 新订单创建完后、检查库存, 根据付款状态决定是否发货等. 可以参考下图, 但实际生产环境中还需要考虑其它业务逻辑, 如订单合法性校验、订单支付状态检测、用户未付款订单超时或取消订单、产品库存该如何更新等.
如图所示, 整个业务流程参考如下:
- 当用户在浏览器中点击”立即订购”时, 发送REST请求至订单控制器(Order Controller)
- 订单控制器(Order Controller)解析请求, 创建新订单指令方至指令网关(Command Gateway), 经指令网关(Command Gateway)转发至指令总线(Command Bus)
- 指令总线(Command Bus)接收指令并转发给订单指令处理器(Order Command Handler)
- 订单指令处理器(Order Command Handler)获取对应产品库存信息
- 基于产品库存信息, 假定订单正常、库存正常情况下减库存, 更新产品Repository, 更新写库(Write DB)并持久化
- Repository更新触发库存更新事件(StockUpdatedEvent)至事件总线(Event Bus), 由事件总线(Event Bus)发送给所有感兴趣的事件监听器
- 由于产品事件处理器(Product Event Handler)订阅了库存更新事件(StockUpdatedEvent), 获取相关事件通知及事件消息
- 基于库存更新事件(StockUpdatedEvent)细节, 产品事件处理器(Product Event Handler)更新产品读模型
- 订单指令处理器(Order Command Handler)发送消息, 创建新订单
- 新订单创建完毕, 向订单Repository发送插入请求, 写入订单实体并持久化于写库(Write DB)
- 发送订单已创建事件(OrderCreatedEvent)至事件总线(Event Bus), 通过事件总线(Event Bus)发送至所有感兴趣的事件监听器
- 由于订单事件处理器(Order Event Handler)订阅了订单已创建事件, 获取相关事件通知及事件消息
- 基于订单已创建事件, 订单事件处理器(Order Event Handler)更新订单读模型
- 用户刷新浏览器, 加载已更新的View
虽然整个下单业务简单, 无非就是用户下单、新建订单、更新库存, 但也请知悉, 如何细粒度量化实现逻辑, 并非易事. 比如在实际生产环境中还需要考虑其它业务复杂性, 如订单合法性校验、订单支付状态检测、用户未付款订单超时或手动取消订单、产品库存复原该如何处理等.
组件梳理
本例所需考虑组件有:
- Aggregates/Aggregate Root (聚合子或聚合根)
- Event Bus, 事件总线
- Command Bus, 命令总线
- Repositories, 如订单 Repository、产品Repository等
- Gateway, 网关, 如指令网关等
- Controller, 如订单Controller等
- Handlers, 如订单指令Handler等
- Event Listener, 事件监听器
SpringBoot应用
应用主类, 代码参考如下:
1 |
|
Aggregate Root建模
其中, 订单Aggregate Root建模代码, 参考如下:
1 | import org.axonframework.domain.AbstractAggregateRoot; |
类似地, 产品Aggregate Root建模, 参考如下:
1 |
|
指令和事件建模
指令(Command)和事件(Event)建模方面, 相对简单, 代码参考如下, 如本例中新建订单指令类似于DTO(数据传输对象, Data Transfer Object).
1 |
|
指令网关、事件总线与指令总线
代码参考如下:
1 |
|
Controller与Handler
订单Controller, 代码参考如下:
1 |
|
订单指令Handler, 代码参考如下:
1 |
|
订单事件Handler, 代码参考如下:
1 |
|
产品事件Handler, 代码参考如下:
1 |
|
事件监听器
事件的发布与订阅、事件监听等功能可通过消息中间件实现, 如RabbitMQ. 对于Spring Boot而言, 几行代码的问题, 此处就不贴代码了.
想学习更多DDD(领域驱动设计)相关知识、提升DDD实战技能, 请点击这里
效果检测
连接数据库, 创建几条测试数据 (注意当运行以上微服务代码时, 会自动创建创建ecom_product
表以及ecom_order
表, 具体原因请参考以上Java代码).
1 | mysql> drop table ecom_order; |
运行:
1 | $ mvn clean && mvn springboot:run |
打开浏览器, 查看页面效果:
点击订购按钮”Order One Now”, 可以看到基本业务功能正常, 示意图参考如下