首页 文章 精选 留言 我的

精选列表

搜索[ORM],共2406篇文章
优秀的个人博客,低调大师

告别 ORM、贫血模型、阻抗失配 | Wow 2.8.6 发布

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动|事件驱动|测试驱动|声明式设计|响应式编程|命令查询职责分离|事件溯源 🎉 更新内容 🎉 新增10 秒钟快速构建基于 Wow 框架的 DDD 项目模板 特性: 新增AggregateRouteSpecFactoryProviderAPI 特性: 增强自定义RouteHandlerFunctionFactoryAPI 依赖: 更新gradle版本v8.5 依赖: 更新插件detekt版本v1.23.4 依赖: 更新插件ksp版本v1.9.21-1.0.15 重构: 使用 CosId 的HostAddressSupplier替换InetUtils,移除Spring-Cloud-Commons依赖 案例: 新增解冻账户(UnfreezeAccount)命令 (经典 DDD 银行转账案例(JAVA)) 修复:AggregateTracingHandlerFunction路由不匹配的问题 特性: 新增10 秒钟快速构建基于 Wow 框架的 DDD 项目模板 模块 说明 api API 层,定义聚合命令(Command)、领域事件(Domain Event)以及查询视图模型(Query View Model)。充当各个模块之间通信的“发布语言”,同时提供详细的 API 文档,助力开发者理解和使用接口。 domain 领域层,包含聚合根和业务约束的实现。聚合根充当领域模型的入口点,负责协调领域对象的操作,确保业务规则的正确执行。业务约束包括领域对象的验证规则、领域事件的处理等。模块内附有详细的领域模型文档,助力团队深入了解业务逻辑。 server 宿主服务,应用程序的启动点。负责整合其他模块,并提供应用程序的入口。涉及配置依赖项、连接数据库、启动 API 服务等任务。此外,server 模块提供了容器化部署的支持,包括 Docker 构建镜像和 Kubernetes 部署文件,简化了部署过程。 code-coverage-report 测试覆盖率,用于生成详细的测试覆盖率报告,以及验证覆盖率是否符合要求。帮助开发团队了解项目测试的全面性和质量。 dependencies 依赖项管理,这个模块负责管理项目的依赖关系,确保各个模块能够正确地引用和使用所需的外部库和工具。 bom 项目的 BOM(Bill of Materials) libs.versions.toml 依赖版本配置文件,明确了项目中各个库的版本,方便团队协作和保持版本的一致性。 deploy Kubernetes 部署文件,提供了在 Kubernetes 上部署应用程序所需的配置文件,简化了部署过程。 Dockerfile server Docker 构建镜像,通过 Dockerfile 文件定义了应用程序的容器化构建步骤,方便部署和扩展。 document 项目文档,包括 UML 图和上下文映射图,为团队成员提供了对整个项目结构和业务逻辑的清晰理解。 架构图 性能测试 (Example) 测试代码:Example 测试场景:加入购物车、下单 命令发送等待模式(WaitStrategy):SENT、PROCESSED 部署 Redis MongoDB Kafka Application-Config Application-Deployment 测试报告 加入购物车 请求 详细报告 (PDF)-SENT 详细报告 (PDF)-PROCESSED WaitStrategy:SENT WaitStrategy:PROCESSED 下单 请求 详细报告 (PDF)-SENT 详细报告 (PDF)-PROCESSED WaitStrategy:SENT WaitStrategy:PROCESSED 事件源 可观测性 OpenAPI (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) 命令等待策略(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 registerCommandAggregatetoRouterFunction 可观测性 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 加载聚合 聚合状态流 发送命令 命令与事件流 Saga - OrderProcessManager (Demo)

优秀的个人博客,低调大师

告别 ORM、贫血模型、阻抗失配 | Wow 2.9.2 发布

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动|事件驱动|测试驱动|声明式设计|响应式编程|命令查询职责分离|事件溯源 更新内容 🎉 🎉 🎉 适配Spring-Boot 3.2.0 依赖: 更新org.springframework.boot:spring-boot-dependencies版本v3.2.0 依赖: 更新me.ahoo.cosid:cosid-bom版本v2.6.0 重构: 使用 CosId 的HostAddressSupplier替换InetUtils,移除Spring-Cloud-Commons依赖 案例: 新增解锁金额(UnfreezeAccount)命令 (经典 DDD 银行转账案例(JAVA)) 架构图 性能测试 (Example) 测试代码:Example 测试场景:加入购物车、下单 命令发送等待模式(WaitStrategy):SENT、PROCESSED 部署 Redis MongoDB Kafka Application-Config Application-Deployment 测试报告 加入购物车 请求 详细报告 (PDF)-SENT 详细报告 (PDF)-PROCESSED WaitStrategy:SENT WaitStrategy:PROCESSED 下单 请求 详细报告 (PDF)-SENT 详细报告 (PDF)-PROCESSED WaitStrategy:SENT WaitStrategy:PROCESSED 事件源 可观测性 OpenAPI (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) 命令等待策略(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 registerCommandAggregatetoRouterFunction 可观测性 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 加载聚合 聚合状态流 发送命令 命令与事件流 Saga - OrderProcessManager (Demo)

优秀的个人博客,低调大师

Wow 2.6.8 发布,告别 ORM、贫血模型、阻抗失配

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动|事件驱动|测试驱动|声明式设计|响应式编程|命令查询职责分离|事件溯源 更新内容 🎉 🎉 🎉 特性(RouteSpec): 命令路由(@CommandRoute)路径参数支持未绑定命令体字段 特性: 支持使用租户ID(TenantId)参数构造状态聚合 依赖: 更新org.testcontainers:testcontainers-bom版本v1.19.1 依赖: 更新io.opentelemetry:opentelemetry-bom版本v1.31.0 依赖: 更新io.mockk:mockk版本v1.13.8 架构图 事件源 可观测性 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) 命令等待策略(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 registerCommandAggregatetoRouterFunction 可观测性 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 加载聚合 聚合状态流 发送命令 命令与事件流 Saga - OrderProcessManager (Demo)

优秀的个人博客,低调大师

Wow 2.5.6 发布,告别 ORM、贫血模型、阻抗失配

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动|事件驱动|测试驱动|声明式设计|响应式编程|命令查询职责分离|事件溯源 更新内容 🎉 🎉 🎉 特性:OpenAPI模块支持ErrorInfoSchema 特性:GivenStage支持when函数 特性: 新增上下文别名前缀到OpenAPI Schema以防止命名冲突 修复: 丢失requestBodyType定义 依赖: 更新CosId版本v2.5.2 依赖: 更新springdoc版本v2.2.0 依赖: 更新kotlin版本v1.9.10 依赖: 更新org.springframework.boot:spring-boot-dependencies版本v3.1.3 依赖: 更新org.testcontainers:testcontainers-bom版本v1.19.0 依赖: 更新io.mockk:mockk版本v1.13.7 依赖: 更新io.opentelemetry:opentelemetry-bom版本v1.9.0 依赖: 更新org.jetbrains.dokka版本v1.29.0 架构图 事件源 可观测性 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) 命令等待策略(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 registerCommandAggregatetoRouterFunction 可观测性 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 加载聚合 聚合状态流 发送命令 命令与事件流 Saga - OrderProcessManager (Demo)

优秀的个人博客,低调大师

Wow 2.5.0 发布,告别 ORM、贫血模型、阻抗失配

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动|事件驱动|测试驱动|声明式设计|响应式编程|命令查询职责分离|事件溯源 更新内容 🎉 🎉 🎉 支持标记忽略事件溯源接口(IgnoreSourcing) 依赖: 更新CosId版本v2.4.0 依赖: 更新io.gitlab.arturbosch.detekt版本v1.23.1 特性: 增强Spring-Boot配置提示 特性: 增强单元测试套件断言失败提示 依赖: 更新com.google.guava:guava版本v32.1.2-jre 特性: 支持标记忽略事件溯源接口(IgnoreSourcing) 应用场景:执行聚合根命令时,业务校验失败需要生成失败事件以便下游订阅者处理。并且不需要溯源领域事件。 触发条件: 领域事件标记ErrorInfo,标记该事件为失败事件 领域事件标记IgnoreSourcing 领域事件版本=1 影响: 忽略该领域事件的溯源,且不会变更聚合版本。 将忽略未初始化的状态聚合发送到状态事件总线。 聚合快照处理器将无法接受到该状态事件,即不会存储到快照仓库。 架构图 事件源 可观测性 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) 命令等待策略(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 registerCommandAggregatetoRouterFunction 可观测性 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 加载聚合 聚合状态流 发送命令 命令与事件流 Saga - OrderProcessManager (Demo)

优秀的个人博客,低调大师

Wow 2.4.5 发布,告别贫血模型、ORM、阻抗失配

基于 DDD、EventSourcing 的现代响应式 CQRS 架构微服务开发框架 领域驱动|事件驱动|测试驱动|声明式设计|响应式编程|命令查询职责分离|事件源 更新内容 🎉 🎉 🎉 依赖: 更新CosId版本v2.2.6 修复: 限界上下文别名(NamedBoundedContext.alias)兼容性问题 重构: 限界上下文别名冲突检测跳过空别名 依赖: 更新org.springframework.boot:spring-boot-dependencies版本v3.1.2 架构图 事件源 可观测性 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) 命令等待策略(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 registerCommandAggregatetoRouterFunction 可观测性 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 加载聚合 聚合状态流 发送命令 命令与事件流 Saga - OrderProcessManager (Demo)

优秀的个人博客,低调大师

ORM 工具 HasorDB 4.3.4 发布,支持 Spring/SpringBoot 集成

介绍 HasorDB是一个全功能数据库访问工具,提供对象映射、丰富的类型处理、动态SQL、存储过程、内置分页方言20+、支持嵌套事务、多数据源、条件构造器、INSERT 策略、多语句/多结果。并兼容 Spring 及 MyBatis 用法。它不依赖任何其它框架,因此可以很方便的和任意一个框架整合在一起使用。 功能特性 熟悉的方式 JdbcTemplate 接口方式(高度兼容 Spring JDBC) Mapper 文件方式(高度兼容 MyBatis) LambdaTemplate (高度接近 MyBatis Plus、jOOQ 和 BeetlSQL) @Insert、@Update、@Delete、@Query、@Callable 注解(类似 JPA) 事务支持 支持 5 个事务隔离级别、7 个事务传播行为(与 Spring tx 相同) 提供 TransactionTemplate、TransactionManager 接口方式声明式事务控制能力(用法与 Spring 相同) 特色优势 支持 分页查询 并且提供多种数据库方言(20+) 支持 INSERT 策略(INTO、UPDATE、IGNORE) 更加丰富的 TypeHandler(MyBatis 40+,HasorDB60+) Mapper XML 支持多语句、多结果 提供独特的@{xxx, expr , xxxxx }规则扩展机制,让动态 SQL 更加简单 支持 存储过程 支持 JDBC 4.2 和 Java8 中时间类型 支持多数据源 Release.Note 支持 Spring Xml 配置方式使用 HasorDB 支持 Spring Boot @MapperScan 方式配置。 DynamicConnection 增加 releaseConnection 方法用于外部数据源管理器的连接释放操作。 优化 Mapper 匹配逻辑,增加 mapper 匹配成功率。 RefMapper 和 SimpleMapper 都标记了 DalMapper 注解 最后 在最后如果您觉得这个工具还不错可以给个 start 多多关注这个工具,地址为:https://gitee.com/zycgit/hasordb 此外如果你想更多了解它,可以在它的官网上详细阅读使用技巧https://www.hasordb.net

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册