1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Wow微服務(wù)開發(fā)框架

        聯(lián)合創(chuàng)作 · 2023-09-28 04:41

        Wow 是基于 DDD、EventSourcing 的現(xiàn)代響應(yīng)式 CQRS 架構(gòu)微服務(wù)開發(fā)框架。

        領(lǐng)域驅(qū)動(dòng) | 事件驅(qū)動(dòng) | 測(cè)試驅(qū)動(dòng) | 聲明式設(shè)計(jì)  響應(yīng)式編程  命令查詢職責(zé)分離  事件源

        架構(gòu)圖

        Wow-Architecture

        事件源

        Wow-EventSourcing

        可觀測(cè)性

        Wow-Observability

        Spring WebFlux 集成

        自動(dòng)注冊(cè) 命令 路由處理函數(shù)(HandlerFunction) ,開發(fā)人員僅需編寫領(lǐng)域模型,即可完成服務(wù)開發(fā)。

        Wow-OpenAPI-Swagger

        測(cè)試套件:80%+ 的測(cè)試覆蓋率輕而易舉

        Given -> When -> Expect .

        Wow-CI-Flow

        前置條件

        • 理解 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì):《實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》、《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì):軟件核心復(fù)雜性應(yīng)對(duì)之道》
        • 理解 命令查詢職責(zé)分離(CQRS)
        • 理解 事件源架構(gòu)
        • 理解 響應(yīng)式編程

        特性

        •  Aggregate Modeling
          •  Single Class
          •  Inheritance Pattern
          •  Aggregation Pattern
        •  Saga Modeling
          •  StatelessSaga
        •  Test Suite
          •  兼容性測(cè)試規(guī)范(TCK)
          •  AggregateVerifier
          •  SagaVerifier
        •  EventSourcing
          • EventStore
            •  MongoDB (Recommend)
            •  R2dbc
              •  Database Sharding
              •  Table Sharding
            •  Redis
          • Snapshot
            •  MongoDB
            •  R2dbc
              •  Database Sharding
              •  Table Sharding
            •  ElasticSearch
            •  Redis (Recommend)
        •  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 CommandAggregate to RouterFunction
        •  可觀測(cè)性
          •  OpenTelemetry
        •  OpenApi
        •  WowMetadata Generator
          •  wow-compiler

        Example

        Example

        測(cè)試套件

        80%+ 的測(cè)試覆蓋率輕而易舉。

        Test Coverage

        Given -> When -> Expect .

        internal class OrderTest {
        
            companion object {
                val SHIPPING_ADDRESS = ShippingAddress("China", "ShangHai", "ShangHai", "HuangPu", "001")
            }
        
            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.toFlux().filter { it.productId == productId }.map { it.quantity }.last()
                    }
                }
                val pricingService = object : PricingService {
                    override fun getProductPrice(productId: String): Mono<BigDecimal> {
                        return orderItems.toFlux().filter { it.productId == productId }.map { it.price }.last()
                    }
                }
                return aggregateVerifier<Order, OrderState>(tenantId = tenantId)
                    .inject(DefaultCreateOrderSpec(inventoryService, pricingService))
                    .given()
                    .`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS))
                    .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()
            }
        
            /**
             * 創(chuàng)建訂單
             */
            @Test
            fun createOrder() {
                mockCreateOrder()
            }
        
            /**
             * 創(chuàng)建訂單-庫(kù)存不足
             */
            @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.toFlux().filter { it.productId == productId }
                            /*
                             * 模擬庫(kù)存不足
                             */
                            .map { it.quantity - 1 }.last()
                    }
                }
                val pricingService = object : PricingService {
                    override fun getProductPrice(productId: String): Mono<BigDecimal> {
                        return orderItems.toFlux().filter { it.productId == productId }.map { it.price }.last()
                    }
                }
        
                aggregateVerifier<Order, OrderState>()
                    .inject(DefaultCreateOrderSpec(inventoryService, pricingService))
                    .given()
                    .`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS))
                    /*
                     * 期望:庫(kù)存不足異常.
                     */
                    .expectErrorType(InventoryShortageException::class.java)
                    .expectStateAggregate {
                        /*
                         * 該聚合對(duì)象處于未初始化狀態(tài),即該聚合未創(chuàng)建成功.
                         */
                        assertThat(it.initialized, equalTo(false))
                    }.verify()
            }
        
            /**
             * 創(chuàng)建訂單-下單價(jià)格與當(dāng)前價(jià)格不一致
             */
            @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.toFlux().filter { it.productId == productId }.map { it.quantity }.last()
                    }
                }
                val pricingService = object : PricingService {
                    override fun getProductPrice(productId: String): Mono<BigDecimal> {
                        return orderItems.toFlux().filter { it.productId == productId }
                            /*
                             * 模擬下單價(jià)格、商品定價(jià)不一致
                             */
                            .map { it.price.plus(BigDecimal.valueOf(1)) }.last()
                    }
                }
                aggregateVerifier<Order, OrderState>()
                    .inject(DefaultCreateOrderSpec(inventoryService, pricingService))
                    .given()
                    .`when`(CreateOrder(customerId, orderItems, SHIPPING_ADDRESS))
                    /*
                     * 期望:價(jià)格不一致異常.
                     */
                    .expectErrorType(PriceInconsistencyException::class.java).verify()
            }
        
            private fun mockPayOrder(): VerifiedStage<OrderState> {
                val verifiedStageAfterCreateOrder = mockCreateOrder()
                val previousState = verifiedStageAfterCreateOrder.stateRoot
                val payOrder = PayOrder(
                    previousState.id,
                    GlobalIdGenerator.generateAsString(),
                    previousState.totalAmount
                )
        
                return verifiedStageAfterCreateOrder
                    .then()
                    .given()
                    /*
                     * 2. 當(dāng)接收到命令
                     */
                    .`when`(payOrder)
                    /*
                     * 3.1 期望將會(huì)產(chǎn)生1個(gè)事件
                     */
                    .expectEventCount(1)
                    /*
                     * 3.2 期望將會(huì)產(chǎn)生一個(gè) OrderPaid 事件 (3.1 可以不需要)
                     */
                    .expectEventType(OrderPaid::class.java)
                    /*
                     * 3.3 期望產(chǎn)生的事件狀態(tài)
                     */
                    .expectEventBody<OrderPaid> {
                        assertThat(it.amount, equalTo(payOrder.amount))
                    }
                    /*
                     * 4. 期望當(dāng)前聚合狀態(tài)
                     */
                    .expectState {
                        assertThat(it.address, equalTo(SHIPPING_ADDRESS))
                        assertThat(it.paidAmount, equalTo(payOrder.amount))
                        assertThat(it.status, equalTo(OrderStatus.PAID))
                    }
                    /*
                     * 完成測(cè)試編排后,驗(yàn)證期望.
                     */
                    .verify()
            }
        
            /**
             * 支付訂單
             */
            @Test
            fun payOrder() {
                mockPayOrder()
            }
        
            /**
             * 支付訂單-超付
             */
            @Test
            fun payOrderWhenOverPay() {
                val verifiedStageAfterCreateOrder = mockCreateOrder()
                val previousState = verifiedStageAfterCreateOrder.stateRoot
                val payOrder = PayOrder(
                    previousState.id,
                    GlobalIdGenerator.generateAsString(),
                    previousState.totalAmount.plus(
                        BigDecimal.valueOf(1)
                    )
                )
                verifiedStageAfterCreateOrder
                    .then()
                    .given()
                    /*
                     * 2. 處理 PayOrder 命令
                     */
                    .`when`(payOrder)
                    /*
                     * 3.1 期望將會(huì)產(chǎn)生倆個(gè)事件分別是: OrderPaid、OrderOverPaid
                     */
                    .expectEventType(OrderPaid::class.java, OrderOverPaid::class.java)
                    /*
                     * 3.2 期望產(chǎn)生的事件狀態(tài)
                     */
                    .expectEventStream {
                        val itr = it.iterator()
                        /*
                         * OrderPaid
                         */
                        val orderPaid = itr.next().body as OrderPaid
                        assertThat(orderPaid.paid, equalTo(true))
                        /*
                         * OrderOverPaid
                         */
                        val orderOverPaid = itr.next().body as OrderOverPaid
                        assertThat(
                            orderOverPaid.overPay,
                            equalTo(payOrder.amount.minus(previousState.totalAmount))
                        )
                    }
                    /*
                     * 4. 期望當(dāng)前聚合狀態(tài)
                     */
                    .expectState {
                        assertThat(it.paidAmount, equalTo(previousState.totalAmount))
                        assertThat(it.status, equalTo(OrderStatus.PAID))
                    }
                    .verify()
            }
        
            /**
             * 發(fā)貨
             */
            @Test
            fun ship() {
                val verifiedStageAfterPayOrder = mockPayOrder()
                val shipOrder = ShipOrder(verifiedStageAfterPayOrder.stateRoot.id)
                verifiedStageAfterPayOrder
                    .then().given()
                    .`when`(shipOrder)
                    .expectEventType(OrderShipped::class.java)
                    /*
                     * 4. 期望當(dāng)前聚合狀態(tài)
                     */
                    .expectState {
                        assertThat(it.status, equalTo(OrderStatus.SHIPPED))
                    }
                    .verify()
            }
        
            @Test
            fun shipGivenUnpaid() {
                val verifiedStageAfterCreateOrder = mockCreateOrder()
                val shipOrder = ShipOrder(verifiedStageAfterCreateOrder.stateRoot.id)
                verifiedStageAfterCreateOrder.then().given()
                    .`when`(shipOrder)
                    .expectErrorType(IllegalStateException::class.java)
                    .expectState {
                        /*
                         * 驗(yàn)證聚合狀態(tài)[未]發(fā)生變更.
                         */
                        assertThat(it.paidAmount, equalTo(BigDecimal.ZERO))
                        assertThat(it.status, equalTo(OrderStatus.CREATED))
                    }
                    .verify()
            }
        
            private fun mockDeleteOrder(): VerifiedStage<OrderState> {
                val verifiedStageAfterCreateOrder = mockCreateOrder()
                return verifiedStageAfterCreateOrder.then().given()
                    .`when`(DeleteAggregate)
                    .expectEventType(AggregateDeleted::class.java)
                    .expectStateAggregate {
                        assertThat(it.deleted, equalTo(true))
                    }
                    .verify()
            }
        
            @Test
            fun deleteOrder() {
                mockDeleteOrder()
            }
        
            @Test
            fun deleteGivenDeleted() {
                val verifiedStageAfterDelete = mockDeleteOrder()
                verifiedStageAfterDelete.then().given()
                    .`when`(DeleteAggregate)
                    .expectErrorType(IllegalAccessDeletedAggregateException::class.java)
                    .expectError<IllegalAccessDeletedAggregateException> {
                        assertThat(it.aggregateId, equalTo(verifiedStageAfterDelete.stateAggregate.aggregateId))
                    }.expectStateAggregate {
                        assertThat(it.deleted, equalTo(true))
                    }
                    .verify()
            }
        }

        設(shè)計(jì)

        聚合建模

        Single Class Inheritance Pattern Aggregation Pattern
        Single Class - Modeling Inheritance Pattern- Modeling Aggregation Pattern- Modeling

        加載聚合

        Load Aggregate

        聚合狀態(tài)流

        Aggregate State Flow

        發(fā)送命令

        Send Command

        命令與事件流

        Command And Event Flow

        Saga - OrderProcessManager (Demo)

        OrderProcessManager

        瀏覽 27
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        編輯 分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        編輯 分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产在线观看av 青青操影院 | 豆花视频在线观看入口地址 | 婷婷丁香五月在线 | 夜夜撸网站 | 高圆圆一区二区三区 | 色综合999 | 久久6精品 | 免费精品无码成人片在线观看 | 久久精品99国产国产精 | 哦┅┅快┅┅用力啊┅美容院 |