????????微服務架構模型有很多種,例如洋蔥架構、CQRS和六邊形架構等。雖然這些架構模式提出的時代和背景不同,但其核心理念都是為了設計出“高內聚,低耦合”的微服務,輕松實現微服務的架構演進。DDD分層架構的出現,使微服務的架構邊界變得越來越清晰,在微服務架構模型中,占有非常重要的位置。那DDD分層架構到底是什么樣?DDD分層架構如何推動架構演進?我們該怎么轉向DDD分層架構?本章將重點解決這些問題 。
1、什么是DDD分層架構
DDD分層架構其實也在不斷發展和演進。早期的DDD分層架構是一種各層都依賴于基礎層的傳統四層架構,后來這種四層架構進一步優化,實現了各層對基礎層的解耦和依賴倒置。
在最早的傳統四層架構中,基礎層被其他層依賴,位于最核心的位置,是其他各層依賴的核心。但實際上領域層才是軟件的核心,所以這種依賴關系是有問題的。后來就采用了依賴倒置設計,各層服務通過倉儲接口訪問基礎層,從而優化了傳統的DDD四層架構,實現了DDD各層對基礎層的解耦 。
我們本章要重點講解的就是優化后的DDD分層架構。DDD分層架構中包含四層,從上到下依次是:用戶接口層、應用層、領域層和基礎層。
1.1 用戶接口層
在很多描述DDD用戶接口層的文章中,對用戶接口層的解釋通常都是這樣的:“用戶接口層負責向用戶顯示信息和解釋用戶指令,這里的用戶可能是用戶、程序、自動化測試和批處理腳本等。”但隨著微服務架構的盛行,大多數應用都采用了前后端分離的設計模式。為了連接前端應用和后端微服務,于是又出現了API網關 。
結合洋蔥模型和端口適配器架構模型,我在這里稍微拓展一下用戶接口層的作用。在微服務面向不同前端應用時,同樣的一段業務邏輯,可能由于渠道不同,而在前端展示的頁面要素不同,因此要求后端微服務返回的數據結果會不同。例如在面向內部員工的PC端應用時,可能要求返回某些對象的全部屬性的數據,而在面向外部客戶的移動端應用時,可能只需要返回幾個關鍵屬性的數據就可以了。
為了避免暴露微服務的核心業務邏輯,防止數據外泄,不能將后端數據直接暴露給前端應用。為此,可以在用戶接口層引入數據傳輸對象(DTO)和門面接口(Facade Interface),通過這些適配器來提供靈活的數據接口,滿足不同前端應用的需求 。
1.2 應用層
應用層主要負責服務的組合和編排,實現業務邏輯。應用服務通過調用領域層的功能來處理用戶請求,并將處理結果返回給用戶。應用層的設計需要關注以下幾個方面:
- 服務編排:根據業務需求,調用多個領域服務,實現業務功能。
- 事務管理:管理業務操作的事務,確保數據一致性。
- 安全控制:處理用戶權限和身份驗證,確保只有合法用戶可以執行操作 。
應用層通常通過應用服務(Application Services)來實現。應用服務是應用層的核心組件,負責處理具體的業務操作。例如,訂單服務的實現可能如下:
public?class?OrderApplicationService?{private?final?OrderRepository orderRepository;private?final?PaymentService paymentService;public?OrderApplicationService(OrderRepository orderRepository, PaymentService paymentService)?{this.orderRepository = orderRepository;this.paymentService = paymentService;}public?void?placeOrder(OrderDTO orderDTO)?{Order?order?=?new?Order(orderDTO);orderRepository.save(order);paymentService.processPayment(order.getPaymentDetails());}public?OrderDTO?getOrder(String orderId)?{Order?order?=?orderRepository.findById(orderId);return?new?OrderDTO(order);}
}
1.3 領域層
領域層是DDD分層架構的核心,負責處理系統的業務邏輯。領域層包含領域模型和領域服務,通過對領域對象和領域行為的建模,實現業務需求 。
領域層的組成
領域層通常包含以下組件:
- 實體(Entity):具有唯一標識符的對象,表示業務中的關鍵概念。
- 值對象(Value Object):無唯一標識符的對象,表示業務中的描述性概念。
- 聚合(Aggregate):一組相關對象的集合,以聚合根(Aggregate Root)為唯一入口。
- 領域服務(Domain Service):處理跨實體的業務邏輯。
- 倉儲(Repository):負責實體的持久化和檢索 。
領域層的職責
- 建模業務邏輯:通過實體、值對象和聚合等模型來表示業務邏輯。
- 執行業務操作:通過領域服務執行復雜的業務操作。
- 維護數據一致性:確保領域模型的狀態在業務操作后保持一致 。
領域層的實現需要結合具體的業務需求進行設計。以下是一個簡單的領域層實現示例:
public?class?Order?{private?OrderId id;private?List<OrderItem> items;private?OrderStatus status;public?Order(OrderId id, List<OrderItem> items)?{this.id = id;this.items = items;this.status = OrderStatus.CREATED;}public?void?addItem(OrderItem item)?{items.add(item);}public?void?removeItem(OrderItem item)?{items.remove(item);}public?void?place()?{if?(items.isEmpty()) {throw?new?IllegalStateException("Cannot place an order with no items.");}this.status = OrderStatus.PLACED;}// getters and other methods
}
1.4 基礎層
基礎層提供系統運行所需的技術支持和基礎服務。基礎層的設計需要考慮系統的性能、可靠性和可擴展性。
基礎層的職責
- 數據持久化:負責將領域對象持久化到數據庫中。
- 消息傳遞:處理系統內外部的消息傳遞,如事件總線、消息隊列等。
- 第三方集成:與外部系統或服務集成,如支付網關、郵件服務等 。
基礎層的實現通常涉及數據庫訪問、消息中間件、外部服務調用等。以下是一個基礎設施層的簡單實現示例:
public?class?JpaOrderRepository?implements?OrderRepository?{private?final?EntityManager entityManager;public?JpaOrderRepository(EntityManager entityManager)?{this.entityManager = entityManager;}@Overridepublic?void?save(Order order)?{entityManager.persist(order);}@Overridepublic?Order?findById(OrderId id)?{return?entityManager.find(Order.class, id);}
}
1.5 DDD分層架構的重要原則
DDD分層架構有一個重要的依賴原則:“每層只能與位于其下方的層發生耦合”。根據耦合的緊密程度,可以分為兩種架構模式:嚴格分層架構和松散分層架構 。
嚴格分層架構
嚴格分層架構要求每一層只能依賴于其下層的接口。這種設計使得系統的各個部分可以獨立演進,但也可能導致較多的層間調用和性能開銷。
松散分層架構
松散分層架構允許上層直接訪問底層的某些服務或資源,從而減少層間調用的開銷。這種設計在某些性能敏感的場景中非常有效,但需要小心管理依賴關系,避免系統變得難以維護。
2、DDD分層架構如何推動架構演進
業務和技術不斷變化,領域模型也會隨之演進,從而影響微服務的功能和邊界。通過DDD分層架構,我們可以實現領域模型和微服務的同步演進,推動微服務架構的演進 。
2.1 微服務架構的演進
在微服務架構的演進過程中,DDD分層架構提供了一種清晰的模型,通過明確各層的職責和邊界,使得系統的擴展和維護更加便捷。各層之間通過接口進行通信,實現了服務的高內聚、低耦合。
2.2 微服務內服務的演進
在微服務內部,服務的演進可以通過領域模型的重構和優化來實現。通過引入新的領域對象和服務,改進現有的業務邏輯,確保系統能夠靈活應對業務需求的變化。
3、三層架構如何演進到DDD分層架構
傳統企業應用大多是單體架構,而單體架構多采用三層架構。三層架構可以部分解決程序內代碼間調用復雜、代碼職責不清的問題,但這種分層是邏輯概念,在物理上它仍然是集中式架構,所以并不適合分布式微服務架構 。
其實,DDD分層架構內的基本要素和三層架構類似,只不過在DDD分層架構中,這些要素被重新歸類,劃分到了不同的層,確定了層與層之間的交互規則和職責邊界。在三層架構向DDD分層架構演進時,主要變化發生在業務邏輯層和數據訪問層 。
業務邏輯層的變化
DDD分層架構對三層架構的業務邏輯層進行了更清晰的劃分,改善了三層架構核心業務邏輯混亂、代碼改動相互影響大的問題。DDD分層架構將三層架構業務邏輯層的業務邏輯拆分到了應用層和領域層,分別以應用服務和領域服務等形式存在。應用服務實現服務的組合和編排,領域服務完成核心領域邏輯,應用服務可以快速響應前端業務和流程的變化,而領域層則更加專注領域模型和實現領域邏輯 。
數據訪問層的變化
數據訪問層的變化主要發生在數據訪問層和基礎層之間。三層架構數據訪問采用DAO方式,而DDD分層架構對數據庫等基礎資源訪問時采用了倉儲設計模式,領域層可以通過倉儲接口訪問基礎資源的實現邏輯。這樣,通過依賴倒置實現了各層對基礎資源的解耦。原來三層架構的第三方工具包、驅動、Common、Utility、Config等通用的、公共的基礎資源統一放到了基礎層 。
另外,DDD分層架構在用戶接口層引入了DTO和facade接口,可以給前端應用提供更靈活的數據和接口適配能力 。
4、 本章小結
DDD分層架構是微服務設計和開發的核心框架。通過用戶接口層、應用層、領域層和基礎層這些層次劃分,可以明確微服務內各層的職能,劃定各領域對象的邊界,確定各領域對象的依賴和協作方式 。
傳統企業架構向DDD分層架構的轉變,可以通過重構業務邏輯層和數據訪問層,采用領域驅動設計的原則和方法,逐步實現系統的演進和優化 。
================================
DDD分層架構詳解
領域驅動設計(DDD,Domain-Driven Design)是一種設計方法論,旨在通過緊密結合業務領域和軟件設計來解決復雜業務問題。DDD提倡從業務需求出發,建立清晰的領域模型,并根據該模型設計系統架構。在DDD的實現中,分層架構是關鍵的設計模式之一。本文將詳細探討DDD分層架構的各個方面,包括其基本概念、各層職責、實現策略及其在實際項目中的應用。
1. DDD分層架構的歷史與演變
DDD分層架構最早的形式是一種各層都依賴于基礎層的傳統四層架構。在這種架構中,基礎層位于核心位置,其他各層依賴于基礎層。然而,隨著軟件架構的不斷發展,這種依賴關系逐漸暴露出問題。為了優化架構設計,依賴倒置原則被引入,各層通過接口訪問基礎層,實現了對基礎層的解耦。
1.1 分層架構的演變
分層架構的演變經歷了多個階段,主要包括三層架構、傳統四層架構和優化后的四層架構。
-
三層架構:傳統的三層架構包括表示層、業務邏輯層和數據訪問層。這種架構可以部分解決代碼職責不清的問題,但在物理上仍然是集中式架構,不適合分布式微服務架構。
-
傳統四層架構:傳統四層架構在三層架構的基礎上增加了基礎層,各層都依賴于基礎層。然而,這種設計并沒有充分考慮領域層的重要性,導致依賴關系不合理。
-
優化后的四層架構:優化后的四層架構通過引入依賴倒置原則,各層通過倉儲接口訪問基礎層,實現了對基礎層的解耦,明確了領域層的核心地位。
2. DDD分層架構的組成
DDD分層架構通常包括四層,從上到下依次是:用戶接口層、應用層、領域層和基礎層。每一層都有明確的職責和邊界,彼此之間通過接口進行通信。
-
用戶接口層(User Interface Layer):負責接收用戶的輸入和返回處理結果。
-
應用層(Application Layer):負責服務的組合和編排,實現業務邏輯。
-
領域層(Domain Layer):包含領域模型和領域邏輯,是系統的核心,負責實現核心業務邏輯。
-
基礎層(Infrastructure Layer):提供通用的技術和基礎服務,包括數據持久化、消息傳遞等。
2.1 用戶接口層
用戶接口層是系統與外部交互的部分,負責處理用戶的輸入并將處理結果返回給用戶。用戶接口層通過API網關連接前端應用和后端微服務。
2.1.1 用戶接口層的職責
-
接收用戶輸入:通過API接收前端或其他系統的請求。
-
展示處理結果:將應用層處理的結果通過API返回給前端或其他系統。
-
輸入驗證:對用戶輸入的數據進行初步驗證,確保數據格式和內容的合法性。
2.1.2 用戶接口層的實現
用戶接口層通常通過RESTful API或GraphQL等技術實現。例如:
@RestController
@RequestMapping("/orders")
public class OrderController {private final OrderApplicationService orderApplicationService;public OrderController(OrderApplicationService orderApplicationService) {this.orderApplicationService = orderApplicationService;}@PostMappingpublic ResponseEntity<Void> placeOrder(@RequestBody OrderDTO orderDTO) {orderApplicationService.placeOrder(orderDTO);return ResponseEntity.status(HttpStatus.CREATED).build();}@GetMapping("/{id}")public ResponseEntity<OrderDTO> getOrder(@PathVariable String id) {OrderDTO orderDTO = orderApplicationService.getOrder(id);return ResponseEntity.ok(orderDTO);}
}
2.2 應用層
應用層負責協調用戶接口層和領域層,執行應用邏輯。應用層不包含領域邏輯,只負責調用領域層的功能,處理用戶請求并返回結果。
2.2.1 應用層的職責
-
服務編排:根據業務需求,調用多個領域服務,實現業務功能。
-
事務管理:管理業務操作的事務,確保數據一致性。
-
安全控制:處理用戶權限和身份驗證,確保只有合法用戶可以執行操作。
2.2.2 應用層的實現
應用層通常通過應用服務(Application Services)來實現。應用服務是應用層的核心組件,負責處理具體的業務操作。以下是一個典型的應用服務實現示例:
public class OrderApplicationService {private final OrderRepository orderRepository;private final PaymentService paymentService;public OrderApplicationService(OrderRepository orderRepository, PaymentService paymentService) {this.orderRepository = orderRepository;this.paymentService = paymentService;}public void placeOrder(OrderDTO orderDTO) {Order order = new Order(orderDTO);orderRepository.save(order);paymentService.processPayment(order.getPaymentDetails());}public OrderDTO getOrder(String orderId) {Order order = orderRepository.findById(orderId);return new OrderDTO(order);}
}
2.3 領域層
領域層是DDD分層架構的核心,負責處理系統的業務邏輯。領域層包含領域模型和領域服務,通過對領域對象和領域行為的建模,實現業務需求。
2.3.1 領域層的組成
領域層通常包含以下組件:
-
實體(Entity):具有唯一標識符的對象,表示業務中的關鍵概念。
-
值對象(Value Object):無唯一標識符的對象,表示業務中的描述性概念。
-
聚合(Aggregate):一組相關對象的集合,以聚合根(Aggregate Root)為唯一入口。
-
領域服務(Domain Service):處理跨實體的業務邏輯。
-
倉儲(Repository):負責實體的持久化和檢索。
2.3.2 領域層的職責
-
建模業務邏輯:通過實體、值對象和聚合等模型來表示業務邏輯。
-
執行業務操作:通過領域服務執行復雜的業務操作。
-
維護數據一致性:確保領域模型的狀態在業務操作后保持一致。
2.3.3 領域層的實現
領域層的實現需要結合具體的業務需求進行設計。以下是一個簡單的領域層實現示例:
public class Order {private OrderId id;private List<OrderItem> items;private OrderStatus status;public Order(OrderId id, List<OrderItem> items) {this.id = id;this.items = items;this.status = OrderStatus.CREATED;}public void addItem(OrderItem item) {items.add(item);}public void removeItem(OrderItem item) {items.remove(item);}public void place() {if (items.isEmpty()) {throw new IllegalStateException("Cannot place an order with no items.");}this.status = OrderStatus.PLACED;}// getters and other methods
}
2.4 基礎層
基礎層提供系統運行所需的技術支持和基礎服務。基礎層的設計需要考慮系統的性能、可靠性和可擴展性。
2.4.1 基礎層的職責
-
數據持久化:負責將領域對象持久化到數據庫中。
-
消息傳遞:處理系統內外部的消息傳遞,如事件總線、消息隊列等。
-
第三方集成:與外部系統或服務集成,如支付網關、郵件服務等。
2.4.2 基礎層的實現
基礎層的實現通常涉及數據庫訪問、消息中間件、外部服務調用等。以下是一個基礎設施層的簡單實現示例:
public class JpaOrderRepository implements OrderRepository {private final EntityManager entityManager;public JpaOrderRepository(EntityManager entityManager) {this.entityManager = entityManager;}@Overridepublic void save(Order order) {entityManager.persist(order);}@Overridepublic Order findById(OrderId id) {return entityManager.find(Order.class, id);}
}
3. DDD分層架構的重要原則
DDD分層架構有一個重要的依賴原則:“每層只能與位于其下方的層發生耦合”。根據耦合的緊密程度,可以分為兩種架構模式:嚴格分層架構和松散分層架構。
3.1 嚴格分層架構
嚴格分層架構要求每一層只能依賴于其下層的接口。這種設計使得系統的各個部分可以獨
立演進,但也可能導致較多的層間調用和性能開銷。
3.2 松散分層架構
松散分層架構允許上層直接訪問底層的某些服務或資源,從而減少層間調用的開銷。這種設計在某些性能敏感的場景中非常有效,但需要小心管理依賴關系,避免系統變得難以維護。
4. DDD分層架構的優勢
DDD分層架構通過明確各層的職責和邊界,實現了系統的高內聚、低耦合,具有以下優勢:
-
提高系統可維護性:每一層都有明確的職責和邊界,代碼更加清晰,便于維護和擴展。
-
增強系統靈活性:通過分層設計,可以在不影響其他層的情況下,對某一層進行修改和優化。
-
促進團隊協作:不同層次的職責劃分明確,團隊成員可以專注于各自負責的層次,提高開發效率。
5. DDD分層架構的實踐
在實際項目中,DDD分層架構的應用需要結合具體的業務需求和技術環境進行調整。以下是一些實踐建議:
5.1 選擇合適的分層策略
根據系統的復雜度和業務需求,選擇合適的分層策略。對于小型項目,可以采用簡化的三層架構;對于大型項目,則可以采用完整的四層架構。
5.2 遵循依賴倒置原則
在DDD分層架構中,低層不應該依賴于高層,高層應該通過接口依賴于低層。這一原則通過依賴倒置(Dependency Inversion Principle, DIP)來實現,有助于降低層之間的耦合。
5.3 結合CQRS模式
命令查詢責任分離(Command Query Responsibility Segregation, CQRS)是一種常見的設計模式,將寫操作和讀操作分離,以提高系統的性能和擴展性。在DDD分層架構中,可以結合CQRS模式,實現更加靈活的架構設計。
5.4 應用事件驅動架構
事件驅動架構(Event-Driven Architecture, EDA)是一種基于事件的系統設計模式,適用于處理復雜業務邏輯和高并發場景。在DDD分層架構中,可以通過領域事件和事件總線,實現各層之間的解耦和異步處理。
5.5 實現自動化測試
自動化測試是確保系統質量的重要手段。在DDD分層架構中,可以通過單元測試、集成測試和端到端測試等多種方式,對各層進行全面測試,確保系統的穩定性和可靠性。
6. 案例分析:電商系統的DDD分層架構
為了更好地理解DDD分層架構的應用,以下以一個電商系統為例,進行詳細的案例分析。
6.1 需求分析
一個典型的電商系統需要處理以下業務需求:
-
用戶管理:注冊、登錄、用戶信息管理等。
-
商品管理:商品的增刪改查、分類管理、庫存管理等。
-
訂單管理:訂單創建、支付、配送、訂單狀態管理等。
-
促銷管理:優惠券、折扣活動等。
6.2 系統架構設計
根據以上需求,可以設計一個基于DDD分層架構的電商系統。系統架構圖如下:
+--------------------+
| 用戶接口層 |
+--------------------+
| 應用層 |
+--------------------+
| 領域層 |
+--------------------+
| 基礎設施層 |
+--------------------+
6.3 各層職責與實現
用戶接口層:負責處理用戶的注冊、登錄、瀏覽商品、下單等操作。可以使用前端框架(如React、Vue)實現。
應用層:負責協調用戶接口層和領域層,處理用戶請求并返回結果。包括用戶服務、商品服務、訂單服務等。
public class OrderApplicationService {private final OrderRepository orderRepository;private final PaymentService paymentService;public OrderApplicationService(OrderRepository orderRepository, PaymentService paymentService) {this.orderRepository = orderRepository;this.paymentService = paymentService;}public void placeOrder(OrderDTO orderDTO) {Order order = new Order(orderDTO);orderRepository.save(order);paymentService.processPayment(order.getPaymentDetails());}public OrderDTO getOrder(String orderId) {Order order = orderRepository.findById(orderId);return new OrderDTO(order);}
}
領域層:包含用戶、商品、訂單等領域模型及其業務邏輯。通過實體、值對象、聚合等模型表示業務邏輯。
public class Order {private OrderId id;private List<OrderItem> items;private OrderStatus status;public Order(OrderId id, List<OrderItem> items) {this.id = id;this.items = items;this.status = OrderStatus.CREATED;}public void addItem(OrderItem item) {items.add(item);}public void removeItem(OrderItem item) {items.remove(item);}public void place() {if (items.isEmpty()) {throw new IllegalStateException("Cannot place an order with no items.");}this.status = OrderStatus.PLACED;}// getters and other methods
}
基礎設施層:提供數據持久化、消息傳遞等服務。包括數據庫訪問層、消息隊列等。
public class JpaOrderRepository implements OrderRepository {private final EntityManager entityManager;public JpaOrderRepository(EntityManager entityManager) {this.entityManager = entityManager;}@Overridepublic void save(Order order) {entityManager.persist(order);}@Overridepublic Order findById(OrderId id) {return entityManager.find(Order.class, id);}
}
6.4 應用CQRS和事件驅動架構
在電商系統中,可以結合CQRS和事件驅動架構,實現讀寫操作的分離和事件處理的解耦。
CQRS:將訂單的寫操作和讀操作分離,通過命令總線處理寫操作,通過查詢總線處理讀操作。
事件驅動架構:在訂單創建、支付完成、訂單狀態變更等關鍵操作時,發布領域事件,通過事件總線傳遞給訂閱者,實現各服務之間的異步解耦。
// 訂單創建事件
public class OrderCreatedEvent {private String orderId;private String userId;private LocalDateTime createTime;// 構造函數、getter和setter方法
}// 發布訂單創建事件
public void placeOrder(OrderDTO orderDTO) {Order order = new Order(orderDTO);orderRepository.save(order);OrderCreatedEvent event = new OrderCreatedEvent(order.getId(), order.getUserId(), LocalDateTime.now());eventBus.publish(event);
}// 處理訂單創建事件
public class OrderCreatedEventHandler {@Subscribepublic void handle(OrderCreatedEvent event) {// 處理訂單創建后的業務邏輯}
}
7. 總結
DDD分層架構通過明確各層的職責和邊界,實現了系統的高內聚、低耦合,提高了系統的可維護性和擴展性。在實際項目中,應用DDD分層架構需要結合具體的業務需求和技術環境,選擇合適的分層策略,并結合CQRS和事件驅動架構等設計模式,實現靈活高效的系統設計。
通過對DDD分層架構的深入理解和實踐應用,我們可以構建出更加健壯和靈活的系統,更好地應對復雜業務需求和快速變化的技術環境。