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