基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架
Spring WebFlux 集成
自动注册 命令 路由处理函数 (
HandlerFunction) ,开发人员仅需编写领域模型,即可完成服务开发。
测试套件:80%+ 的测试覆盖率轻而易举
Given -> When -> Expect .
前置条件
- 理解 领域驱动设计:《实现领域驱动设计》、《领域驱动设计:软件核心复杂性应对之道》
 - 理解 命令查询职责分离(CQRS)
 - 理解 事件溯源架构
 - 理解 响应式编程
 
特性
-  Aggregate Modeling    
- Single Class
 - Inheritance Pattern
 - Aggregation Pattern
 
 -  Saga Modeling    
-  
StatelessSaga 
 -  
 -  Test Suite    
- 兼容性测试规范(TCK)
 -  
AggregateVerifier -  
SagaVerifier 
 -  EventSourcing    
- EventStore      
- MongoDB (Recommend)
 -  R2dbc        
- Database Sharding
 - Table Sharding
 
 - Redis
 
 - Snapshot      
- MongoDB
 -  R2dbc        
- Database Sharding
 - Table Sharding
 
 - ElasticSearch
 - Redis (Recommend)
 
 
 - EventStore      
 -  命令等待策略(
WaitStrategy)-  
SENT: 命令发送成功后发送完成信号 -  
PROCESSED: 命令处理完成后发送完成信号 -  
SNAPSHOT: 快照生成完成后发送完成信号 -  
PROJECTED: 命令产生的事件被投影后发送完成信号 
 -  
 -  CommandBus    
-  
InMemoryCommandBus -  
KafkaCommandBus(Recommend) -  
RedisCommandBus -  
LocalFirstCommandBus 
 -  
 -  DomainEventBus    
-  
InMemoryDomainEventBus -  
KafkaDomainEventBus(Recommend) -  
RedisDomainEventBus -  
LocalFirstDomainEventBus 
 -  
 -  StateEventBus    
-  
InMemoryStateEventBus -  
KafkaStateEventBus(Recommend) -  
RedisStateEventBus -  
LocalFirstStateEventBus 
 -  
 -  Spring 集成    
- Spring Boot Auto Configuration
 -  Automatically register 
CommandAggregatetoRouterFunction 
 -  可观测性    
- OpenTelemetry
 
 - OpenAPI
 -  
WowMetadataGenerator-  
wow-compiler 
 -  
 
Example
Example
单元测试套件
80%+ 的测试覆盖率轻而易举。
Given -> When -> Expect .
Aggregate Unit Test (AggregateVerifier)
  Aggregate Test
 internal class OrderTest {      private fun mockCreateOrder(): VerifiedStage<OrderState> {         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()             }         }         return 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 createOrder() {         mockCreateOrder()     }      @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()     }      /** * 创建订单-下单价格与当前价格不一致 */     @Test     fun createOrderWhenPriceInconsistency() {         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.plus(BigDecimal.valueOf(1)) }.first().toMono()             }         }         aggregateVerifier<Order, OrderState>()             .inject(DefaultCreateOrderSpec(inventoryService, pricingService))             .given()             .`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS, false))             /* * 期望:价格不一致异常. */             .expectErrorType(PriceInconsistencyException::class.java).verify()     } }  Saga Unit Test (SagaVerifier)
  Saga Test
 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 | 
|---|---|---|






		

还没有评论,来说两句吧...