🎉 领域模型即服务 | Wow 2.12.1 发布
基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架
领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件溯源
更新内容
增强 事件补偿控制台
- 特性(
dashboard): 支持在事件补偿控制台配置执行失败的重试策略 - 特性(
dashboard): 支持查看事务补偿-历史记录 - 特性(
dashboard): 添加事件补偿-正在执行导航 - 特性(
dashboard): 添加事件补偿通知快速打开执行失败链接 - 特性(
OpenAPI): 添加SnapshotConverter/StateEventConverter/EventStreamConverter/DomainEventConverter以适配 Wow 内置序列化器 - OpenAPI-Schema - 特性(
CommandGateawy): 添加sendAndWaitForSnapshotAPI - 依赖: 升级
org.springframework.boot:spring-boot-dependenciesv3.2.1 - 依赖: 升级
org.jetbrains.kotlin.kaptv1.9.22 - 依赖: 升级
angularv17.0.8
事件补偿控制台
快速开始
使用 Wow 项目模板快速创建基于 Wow 框架的 DDD 项目。
特性概览
架构图
性能测试 (Example)
- 测试代码:Example
- 测试场景:加入购物车、下单
- 命令发送等待模式(
WaitStrategy):SENT、PROCESSED
部署
测试报告
加入购物车
命令等待策略(
WaitStrategy)为SENT模式,加入购物车命令(AddCartItem)写请求 API 经过 2 分钟的压测,平均 TPS 为 59625,峰值为 82312,平均响应时间为 29 毫秒。
命令等待策略(
WaitStrategy)为PROCESSED模式,加入购物车命令(AddCartItem)写请求 API 经过 2 分钟的压测,平均 TPS 为 18696,峰值为 24141,平均响应时间为 239 毫秒。
下单
命令等待策略(
WaitStrategy)为SENT模式,下单命令(CreateOrder)写请求 API 经过 2 分钟的压测,平均 TPS 为 47838,峰值为 86200,平均响应时间为 217 毫秒。
命令等待策略(
WaitStrategy)为PROCESSED模式,下单命令(CreateOrder)写请求 API 经过 2 分钟的压测,平均 TPS 为 18230,峰值为 25506,平均响应时间为 268 毫秒。
事件源
可观测性
OpenAPI (Spring WebFlux 集成)
自动注册 命令 路由处理函数 (
HandlerFunction) ,开发人员仅需编写领域模型,即可完成服务开发。
测试套件:80%+ 的测试覆盖率轻而易举
Given -> When -> Expect .
前置条件
- 理解 领域驱动设计:《实现领域驱动设计》、《领域驱动设计:软件核心复杂性应对之道》
- 理解 命令查询职责分离(CQRS)
- 理解 事件源架构
- 理解 响应式编程
Example
订单服务(Kotlin)
银行转账(JAVA)
单元测试套件
80%+ 的测试覆盖率轻而易举。
Given -> When -> Expect .
Aggregate Unit Test (AggregateVerifier)
internal class OrderTest {
@Test
private fun createOrder() {
val tenantId = GlobalIdGenerator.generateAsString()
val customerId = GlobalIdGenerator.generateAsString()
val orderItem = OrderItem(
GlobalIdGenerator.generateAsString(),
GlobalIdGenerator.generateAsString(),
BigDecimal.valueOf(10),
10,
)
val orderItems = listOf(orderItem)
val inventoryService = object : InventoryService {
override fun getInventory(productId: String): Mono<Int> {
return orderItems.filter { it.productId == productId }.map { it.quantity }.first().toMono()
}
}
val pricingService = object : PricingService {
override fun getProductPrice(productId: String): Mono<BigDecimal> {
return orderItems.filter { it.productId == productId }.map { it.price }.first().toMono()
}
}
aggregateVerifier<Order, OrderState>(tenantId = tenantId)
.inject(DefaultCreateOrderSpec(inventoryService, pricingService))
.given()
.`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS, false))
.expectEventCount(1)
.expectEventType(OrderCreated::class.java)
.expectStateAggregate {
assertThat(it.aggregateId.tenantId, equalTo(tenantId))
}
.expectState {
assertThat(it.id, notNullValue())
assertThat(it.customerId, equalTo(customerId))
assertThat(it.address, equalTo(SHIPPING_ADDRESS))
assertThat(it.items, equalTo(orderItems))
assertThat(it.status, equalTo(OrderStatus.CREATED))
}
.verify()
}
@Test
fun createOrderGivenEmptyItems() {
val customerId = GlobalIdGenerator.generateAsString()
aggregateVerifier<Order, OrderState>()
.inject(mockk<CreateOrderSpec>(), "createOrderSpec")
.given()
.`when`(CreateOrder(customerId, listOf(), SHIPPING_ADDRESS, false))
.expectErrorType(IllegalArgumentException::class.java)
.expectStateAggregate {
/*
* 该聚合对象处于未初始化状态,即该聚合未创建成功.
*/
assertThat(it.initialized, equalTo(false))
}.verify()
}
/**
* 创建订单-库存不足
*/
@Test
fun createOrderWhenInventoryShortage() {
val customerId = GlobalIdGenerator.generateAsString()
val orderItem = OrderItem(
GlobalIdGenerator.generateAsString(),
GlobalIdGenerator.generateAsString(),
BigDecimal.valueOf(10),
10,
)
val orderItems = listOf(orderItem)
val inventoryService = object : InventoryService {
override fun getInventory(productId: String): Mono<Int> {
return orderItems.filter { it.productId == productId }
/*
* 模拟库存不足
*/
.map { it.quantity - 1 }.first().toMono()
}
}
val pricingService = object : PricingService {
override fun getProductPrice(productId: String): Mono<BigDecimal> {
return orderItems.filter { it.productId == productId }.map { it.price }.first().toMono()
}
}
aggregateVerifier<Order, OrderState>()
.inject(DefaultCreateOrderSpec(inventoryService, pricingService))
.given()
.`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS, false))
/*
* 期望:库存不足异常.
*/
.expectErrorType(InventoryShortageException::class.java)
.expectStateAggregate {
/*
* 该聚合对象处于未初始化状态,即该聚合未创建成功.
*/
assertThat(it.initialized, equalTo(false))
}.verify()
}
}
Saga Unit Test (SagaVerifier)
class CartSagaTest {
@Test
fun onOrderCreated() {
val orderItem = OrderItem(
GlobalIdGenerator.generateAsString(),
GlobalIdGenerator.generateAsString(),
BigDecimal.valueOf(10),
10,
)
sagaVerifier<CartSaga>()
.`when`(
mockk<OrderCreated> {
every {
customerId
} returns "customerId"
every {
items
} returns listOf(orderItem)
every {
fromCart
} returns true
},
)
.expectCommandBody<RemoveCartItem> {
assertThat(it.id, equalTo("customerId"))
assertThat(it.productIds, hasSize(1))
assertThat(it.productIds.first(), equalTo(orderItem.productId))
}
.verify()
}
}
设计
聚合建模
| Single Class | Inheritance Pattern | Aggregation Pattern |
|---|---|---|














