強烈建議在項目中使用四層架構模型
經典的四層架構將軟件系統分為四個層次,每個層次都有不同的職責和功能。經典的四層 架構如圖1所示。
圖1 經典的四層架構
1.? 用戶接口(User Interface)層
用戶接口層將應用層的服務按照一定協議對外暴露。用戶接口層接收用戶請求,并將請求的參數經過處理后,傳遞給應用層進行處理,最后將應用層的處理結果按照一定的協議向調用 者返回。
用戶接口層是應用的最上層,通常表現為 Controller 接口、RPC 服務提供者的實現類、定 時任務、消息隊列的監聽器等。
用戶接口層不應包含任何業務處理邏輯,僅用于暴露應用層服務。用戶接口層的代碼應該非常簡單。
2.? 應用(Application)層
應用層協調領域模型和基礎設施層完成業務操作。應用層自身不包含業務邏輯處理的代 碼,它收到來自用戶接口層的請求后,通過基礎設施層加載領域模型(聚合根),再由領域模 型完成業務操作,最后由基礎設施層持久化領域模型。
應用層的代碼也應該是簡單的,僅用于編排基礎設施和領域模型的執行過程,既不涉及業務操作,也不涉及基礎設施的技術實現。
3.? 領域(Domain)層
領域層是對業務進行領域建模的結果,包含所有的領域模型,如實體、值對象、領域服務等。
所有的業務概念、業務規則、業務流程都應在領域層中表達。
領域層不包括任何技術細節,相關的倉儲、工廠、網關等基礎設施應先在領域層進行定義,然后交給基礎設施層或者應用層進行實現。
4.? 基礎設施(Infrastructure)層
基礎設施層負責實現領域層定義的基礎設施接口,例如,加載和保存聚合根的倉儲 (Repository)接口、調用外部服務的網關(Gateway)接口、發布領域事件到消息中間件的消 息發布(Publisher)接口等。基礎設施層實現這些接口后,供應用層調用。
基礎設施層僅包含技術實現細節,不包含任何業務處理邏輯。基礎設施層接口的輸入和輸 出應該是領域模型或基礎數據類型。
端口和適配器架構
端口和適配器架構(Ports and Adapters Architecture)又被稱為六邊形架構(Hexagonal Architecture),其核心思想是將業務邏輯從技術細節中解耦,使業務邏輯能夠獨立于任何特定的技術實現。
端口和適配器架構通過引入兩個關鍵概念來達到這個目標:端口(Port)和適配 器(Adapter)。
端口是系統與外部進行交互的接口,它定義了系統對外提供的服務以及需要外部提供的支持。
“定義系統對外提供的服務”通常是指定義可以被外部系統調用的接口,將業務邏輯實現在接 口的實現類中,這種端口屬于入站端口(Inbound Port)。
“定義需要外部提供的支持”,是指執行業務邏輯的過程中,有時候需要依賴外部服務(例如從外部服務加載某些數據以用于完成計算),此時定義一個接口,通過調用該接口完成外部調用,這種端口屬于出站端口(Outbound Port)。
適配器則細分為主動適配器(Driving Adapter)和被動適配器(Driven Adapter)兩種。主 動適配器用于對外暴露端口,例如將端口暴露為 RESTful 接口,或者將端口暴露為 RPC 服務;被動適配器用于實現業務邏輯執行過程中需要使用的端口,如外部調用網關等。
六邊形架構如圖2所示。
圖2 六邊形架構
端口和適配器之間的交互關系如圖 2-4 所示。
圖3 端口和適配器之間的交互關系
主動適配器偽代碼如下。
/**
* 主動適配器 , 將創建文章的 Port 暴露為 HTTP 服務
*/
@RestController
public class ArticleController {
@Resource
private ArticleService service;
@RequestMapping("/create")
public void create(DTO dto) {
service.create(dto);
}
}
進站端口偽代碼如下。
public interface ArticleService {
/**
* 端口和適配器架構中的 Port, 提供創建文章的能力
* 這是一個進站端口
* @param dto
*/
void create(DTO dto);
}
出站端口偽代碼如下。
public interface AuthorServiceGateway {
/**
* 端口和適配器架構中的 Port, 查詢作者信息
* 這是一個出站端口
* @param authorId
* @return
*/
AuthorDto queryAuthor(String authorId);
}
被動適配器偽代碼如下。
/**
* 被動適配器
*/
public interface AuthorServiceGatewayImpl implements AuthorServiceGateway {
/**
* 作家 RPC 服務
*/
@Resource
private AuthorServiceRpc rpc;
AuthorDto queryAuthor(String authorId) {
// 拼裝報文
AuthorRequest req = this.createRequest(authorId);
// 執行 RPC 查詢
AuthorResponse res = rpc.queryAuthor();
// 解析查詢結果并返回
return this.handleAuthorResponse(res);
}
}