目錄 領(lǐng)域驅(qū)動(dòng)實(shí)踐總結(jié)二:架構(gòu)分析與代碼設(shè)計(jì) 5.從三層架構(gòu)向 DDD 分層架構(gòu)演進(jìn) (四)三種微服務(wù)架構(gòu)模型的對(duì)比和分析 二、領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)分層架構(gòu)與微服務(wù)代碼模型 2.用戶(hù)接口層目錄結(jié)構(gòu)、職能和代碼形態(tài) 3.應(yīng)用層目錄結(jié)構(gòu)、職能和代碼形態(tài) 4.領(lǐng)域?qū)幽夸浗Y(jié)構(gòu)、職能和代碼形態(tài) 5.基礎(chǔ)層層目錄結(jié)構(gòu)、職能和代碼形態(tài) (二)應(yīng)用層的領(lǐng)域?qū)ο蠓治?/a> (三)領(lǐng)域?qū)拥念I(lǐng)域?qū)ο蠓治?/a> 四、正確認(rèn)識(shí)服務(wù)和數(shù)據(jù)在微服務(wù)各層的協(xié)作 (一)正確認(rèn)識(shí)服務(wù)的協(xié)作 2. 服務(wù)的調(diào)用(三類(lèi)主要場(chǎng)景) (二)正確認(rèn)識(shí)服務(wù)數(shù)據(jù)的協(xié)作 2.領(lǐng)域?qū)訑?shù)據(jù)協(xié)作 5.前端應(yīng)用數(shù)據(jù)協(xié)作 領(lǐng)域驅(qū)動(dòng)實(shí)踐總結(jié)二:架構(gòu)分析與代碼設(shè)計(jì)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)DDD是一種設(shè)計(jì)思想,它可以同時(shí)指導(dǎo)中臺(tái)業(yè)務(wù)建模和微服務(wù)設(shè)計(jì)(中臺(tái)本質(zhì)是業(yè)務(wù)模型,微服務(wù)是業(yè)務(wù)模型的系統(tǒng)落地),領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)強(qiáng)調(diào)領(lǐng)域模型和微服務(wù)設(shè)計(jì)的一體性,先有領(lǐng)域模型然后才有微服務(wù),而不是脫離領(lǐng)域模型來(lái)談微服務(wù)設(shè)計(jì)。 微服務(wù)拆分困境產(chǎn)生的根本原因:不知道業(yè)務(wù)或者微服務(wù)的邊界到底在什么地方。 DDD 核心思想:通過(guò)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)方法定義領(lǐng)域模型,從而確定業(yè)務(wù)和應(yīng)用邊界,保證業(yè)務(wù)模型與代碼模型的一致性。 對(duì)于領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的學(xué)習(xí)做的總結(jié)主要寫(xiě)三篇博客,主要包括三部分:基本理論總結(jié)與分析、架構(gòu)分析與代碼設(shè)計(jì)、具體應(yīng)用設(shè)計(jì)分析,主要參考的資料為極客時(shí)間的歐創(chuàng)新架構(gòu)師的《DDD》實(shí)戰(zhàn),其他參考書(shū)籍在文章下方的參考書(shū)籍中。 本次主要總結(jié)DDD架構(gòu)分析與代碼設(shè)計(jì): 一、微服務(wù)架構(gòu)模型的對(duì)比與選擇微服務(wù)架構(gòu)模型現(xiàn)有的選擇模型包括:整潔架構(gòu)、CQRS 和六邊形架構(gòu)、DDD 分層架構(gòu)等。 (注:CQRS架構(gòu)之前博客中有講,本次不做分析) 每種架構(gòu)模式雖然提出的時(shí)代和背景不同,但其核心理念都是為了設(shè)計(jì)出“高內(nèi)聚低耦合”的架構(gòu),輕松實(shí)現(xiàn)架構(gòu)演進(jìn)。 DDD 分層架構(gòu)的思想使架構(gòu)邊界變得越來(lái)越清晰,它在微服務(wù)架構(gòu)模型中,占有非常重要的位置。建議選擇DDD 分層架構(gòu)。 (一)整潔架構(gòu)在整潔架構(gòu)里,同心圓代表應(yīng)用軟件的不同部分,從里到外依次是領(lǐng)域模型、領(lǐng)域服務(wù)、應(yīng)用服務(wù)和最外圍的容易變化的內(nèi)容,比如用戶(hù)界面和基礎(chǔ)設(shè)施。 整潔架構(gòu)最主要的原則是依賴(lài)原則,它定義了各層的依賴(lài)關(guān)系,越往里依賴(lài)越低,代碼級(jí)別越高,越是核心能力。外圓代碼依賴(lài)只能指向內(nèi)圓,內(nèi)圓不需要知道外圓的任何情況。 (二)六邊形架構(gòu)六邊形架構(gòu)的核心理念是:應(yīng)用是通過(guò)端口與外部進(jìn)行交互的。 也就是說(shuō),在下圖的六邊形架構(gòu)中,紅圈內(nèi)的核心業(yè)務(wù)邏輯(應(yīng)用程序和領(lǐng)域模型)與外部資源(包括 APP、Web 應(yīng)用以及數(shù)據(jù)庫(kù)資源等)完全隔離,僅通過(guò)適配器進(jìn)行交互。它解決了業(yè)務(wù)邏輯與用戶(hù)界面的代碼交錯(cuò)問(wèn)題,很好地實(shí)現(xiàn)了前后端分離。 六邊形架構(gòu)各層的依賴(lài)關(guān)系與整潔架構(gòu)一樣,都是由外向內(nèi)依賴(lài)。 六邊形架構(gòu)的一個(gè)端口可能對(duì)應(yīng)多個(gè)外部系統(tǒng),不同的外部系統(tǒng)也可能會(huì)使用不同的適配器,由適配器負(fù)責(zé)協(xié)議轉(zhuǎn)換。這就使得應(yīng)用程序能夠以一致的方式被用戶(hù)、程序、自動(dòng)化測(cè)試和批處理腳本使用。 (三)DDD 分層架構(gòu)從上到下依次是:用戶(hù)接口層、應(yīng)用層、領(lǐng)域?qū)雍突A(chǔ)層。 1.用戶(hù)接口層用戶(hù)接口層負(fù)責(zé)向用戶(hù)顯示信息和解釋用戶(hù)指令。 這里的用戶(hù)可能是:用戶(hù)、程序、自動(dòng)化測(cè)試和批處理腳本等等。 2.應(yīng)用層應(yīng)用層是很薄的一層,理論上不應(yīng)該有業(yè)務(wù)規(guī)則或邏輯,主要面向用例和流程相關(guān)的操作。 位于領(lǐng)域?qū)又?,領(lǐng)域?qū)影鄠€(gè)聚合,所以它可以協(xié)調(diào)多個(gè)聚合的服務(wù)和領(lǐng)域?qū)ο笸瓿煞?wù)編排和組合,協(xié)作完成業(yè)務(wù)操作。 應(yīng)用層也是微服務(wù)之間交互的通道,它可以調(diào)用其它微服務(wù)的應(yīng)用服務(wù),完成微服務(wù)之間的服務(wù)組合和編排。 注意:
3.領(lǐng)域?qū)?/h3>領(lǐng)域?qū)拥淖饔檬?strong>實(shí)現(xiàn)企業(yè)核心業(yè)務(wù)邏輯,通過(guò)各種校驗(yàn)手段保證業(yè)務(wù)的正確性。 領(lǐng)域?qū)?span>主要體現(xiàn)領(lǐng)域模型的業(yè)務(wù)能力,它用來(lái)表達(dá)業(yè)務(wù)概念、業(yè)務(wù)狀態(tài)和業(yè)務(wù)規(guī)則。 領(lǐng)域?qū)影?span>聚合根、實(shí)體、值對(duì)象、領(lǐng)域服務(wù)等領(lǐng)域模型中的領(lǐng)域?qū)ο蟆?/p> 注意:
4.基礎(chǔ)層基礎(chǔ)層是貫穿所有層的,它的作用就是為其它各層提供通用的技術(shù)和基礎(chǔ)服務(wù),包括第三方工具、驅(qū)動(dòng)、消息中間件、網(wǎng)關(guān)、文件、緩存以及數(shù)據(jù)庫(kù)等。比較常見(jiàn)的功能還是提供數(shù)據(jù)庫(kù)持久化。 基礎(chǔ)層包含基礎(chǔ)服務(wù),它采用依賴(lài)倒置設(shè)計(jì),封裝基礎(chǔ)資源服務(wù),實(shí)現(xiàn)應(yīng)用層、領(lǐng)域?qū)优c基礎(chǔ)層的解耦,降低外部資源變化對(duì)應(yīng)用的影響。 5.從三層架構(gòu)向 DDD 分層架構(gòu)演進(jìn)DDD 分層架構(gòu)中的要素其實(shí)和三層架構(gòu)類(lèi)似,只是在 DDD 分層架構(gòu)中,這些要素被重新歸類(lèi),重新劃分了層,確定了層與層之間的交互規(guī)則和職責(zé)邊界。
(四)三種微服務(wù)架構(gòu)模型的對(duì)比和分析
二、領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)分層架構(gòu)與微服務(wù)代碼模型DDD 并沒(méi)有給出標(biāo)準(zhǔn)的代碼模型,不同的人可能會(huì)有不同理解。這里我們?cè)谑褂玫臅r(shí)候還是建議按照歐創(chuàng)新架構(gòu)師總結(jié)的來(lái)進(jìn)行適用,具體如下: (一)代碼模型總目錄結(jié)構(gòu)根據(jù) DDD 分層架構(gòu)模型建立了標(biāo)準(zhǔn)的微服務(wù)代碼模型,在代碼模型里面,各代碼對(duì)象各據(jù)其位、各司其職,共同協(xié)作完成微服務(wù)的業(yè)務(wù)邏輯。它包括用戶(hù)接口層、應(yīng)用層、領(lǐng)域?qū)雍突A(chǔ)層,分層架構(gòu)各層的職責(zé)邊界非常清晰,又能有條不紊地分層協(xié)作。
業(yè)務(wù)邏輯從領(lǐng)域?qū)?、?yīng)用層到用戶(hù)接口層逐層封裝和協(xié)作,對(duì)外提供靈活的服務(wù),既實(shí)現(xiàn)了各層的分工,又實(shí)現(xiàn)了各層的協(xié)作。 1.微服務(wù)一級(jí)目錄結(jié)構(gòu)微服務(wù)一級(jí)目錄是按照 DDD 分層架構(gòu)的分層職責(zé)來(lái)定義的。從下面這張圖中,我們可以看到,在代碼模型里分別為用戶(hù)接口層、應(yīng)用層、領(lǐng)域?qū)雍突A(chǔ)層,建立了 interfaces、application、domain 和 infrastructure 四個(gè)一級(jí)代碼目錄。 2.用戶(hù)接口層目錄結(jié)構(gòu)、職能和代碼形態(tài)主要存放用戶(hù)接口層與前端交互、展現(xiàn)數(shù)據(jù)相關(guān)的代碼。前端應(yīng)用通過(guò)這一層的接口,向應(yīng)用服務(wù)獲取展現(xiàn)所需的數(shù)據(jù)。這一層主要用來(lái)處理用戶(hù)發(fā)送的 Restful 請(qǐng)求,解析用戶(hù)輸入的配置文件,并將數(shù)據(jù)傳遞給 Application 層。數(shù)據(jù)的組裝、數(shù)據(jù)傳輸格式以及 Facade 接口等代碼都會(huì)放在這一層目錄里。 具體如下:
3.應(yīng)用層目錄結(jié)構(gòu)、職能和代碼形態(tài)主要存放應(yīng)用層服務(wù)組合和編排相關(guān)的代碼。應(yīng)用服務(wù)向下基于微服務(wù)內(nèi)的領(lǐng)域服務(wù)或外部微服務(wù)的應(yīng)用服務(wù)完成服務(wù)的編排和組合,向上為用戶(hù)接口層提供各種應(yīng)用數(shù)據(jù)展現(xiàn)支持服務(wù)。應(yīng)用服務(wù)和事件等代碼會(huì)放在這一層目錄里。 具體如下:
4.領(lǐng)域?qū)幽夸浗Y(jié)構(gòu)、職能和代碼形態(tài)主要存放領(lǐng)域?qū)雍诵臉I(yè)務(wù)邏輯相關(guān)的代碼。領(lǐng)域?qū)涌梢园?span>多個(gè)聚合代碼包,它們共同實(shí)現(xiàn)領(lǐng)域模型的核心業(yè)務(wù)邏輯。聚合以及聚合內(nèi)的實(shí)體、方法、領(lǐng)域服務(wù)和事件等代碼會(huì)放在這一層目錄里。 具體如下:
5.基礎(chǔ)層層目錄結(jié)構(gòu)、職能和代碼形態(tài)主要存放基礎(chǔ)資源服務(wù)相關(guān)的代碼,為其它各層提供的通用技術(shù)能力、三方軟件包、數(shù)據(jù)庫(kù)服務(wù)、配置和基礎(chǔ)資源服務(wù)的代碼都會(huì)放在這一層目錄里。 具體如下:
(二)應(yīng)用層的領(lǐng)域?qū)ο蠓治?/h2>應(yīng)用層的主要領(lǐng)域?qū)ο笫菓?yīng)用服務(wù)和事件的發(fā)布以及訂閱。 在事件風(fēng)暴或領(lǐng)域故事分析時(shí),我們往往會(huì)根據(jù)用戶(hù)或系統(tǒng)發(fā)起的命令,來(lái)設(shè)計(jì)服務(wù)或?qū)嶓w方法。為了響應(yīng)這個(gè)命令,我們需要分析和記錄:
在嚴(yán)格分層架構(gòu)模式下,不允許服務(wù)的跨層調(diào)用,每個(gè)服務(wù)只能調(diào)用它的下一層服務(wù)。服務(wù)從下到上依次為:實(shí)體方法、領(lǐng)域服務(wù)和應(yīng)用服務(wù)。建議采用服務(wù)逐層封裝的方式,服務(wù)的封裝和調(diào)用主要有以下幾種方式: 1.實(shí)體方法的封裝實(shí)體方法是最底層的原子業(yè)務(wù)邏輯。
經(jīng)過(guò)逐層服務(wù)封裝,實(shí)體方法就可以暴露給上面不同的層,實(shí)現(xiàn)跨層調(diào)用。 封裝時(shí)服務(wù)前面的名字可以保持一致,你可以用 *DomainService 或 *AppService 后綴來(lái)區(qū)分領(lǐng)域服務(wù)或應(yīng)用服務(wù)。 2.領(lǐng)域服務(wù)的組合和封裝領(lǐng)域服務(wù)會(huì)對(duì)多個(gè)實(shí)體和實(shí)體方法進(jìn)行組合和編排,供應(yīng)用服務(wù)調(diào)用。 如果它需要暴露給用戶(hù)接口層,領(lǐng)域服務(wù)就需要封裝成應(yīng)用服務(wù)。 3.應(yīng)用服務(wù)的組合和編排應(yīng)用服務(wù)會(huì)對(duì)多個(gè)領(lǐng)域服務(wù)進(jìn)行組合和編排,暴露給用戶(hù)接口層,供前端應(yīng)用調(diào)用。 多個(gè)應(yīng)用服務(wù)可能會(huì)對(duì)多個(gè)同樣的領(lǐng)域服務(wù)重復(fù)進(jìn)行同樣業(yè)務(wù)邏輯的組合和編排。當(dāng)出現(xiàn)這種情況時(shí),就需要分析是不是領(lǐng)域服務(wù)可以整合了??梢詫⑦@幾個(gè)不斷重復(fù)組合的領(lǐng)域服務(wù),合并到一個(gè)領(lǐng)域服務(wù)中實(shí)現(xiàn),這樣領(lǐng)域模型將會(huì)越來(lái)越精煉,更能適應(yīng)業(yè)務(wù)的要求。 應(yīng)用服務(wù)類(lèi)放在應(yīng)用層 Service 目錄結(jié)構(gòu)下。領(lǐng)域事件的發(fā)布和訂閱類(lèi)放在應(yīng)用層 Event 目錄結(jié)構(gòu)下。 (三)領(lǐng)域?qū)拥念I(lǐng)域?qū)ο蠓治?/h2>事件風(fēng)暴結(jié)束時(shí),領(lǐng)域模型聚合內(nèi)一般會(huì)有:聚合、實(shí)體、命令和領(lǐng)域事件等領(lǐng)域?qū)ο?/span>。 在完成故事分析和微服務(wù)設(shè)計(jì)后,微服務(wù)的聚合內(nèi)一般會(huì)有:聚合、聚合根、實(shí)體、值對(duì)象、領(lǐng)域事件、領(lǐng)域服務(wù)和倉(cāng)儲(chǔ)等領(lǐng)域?qū)ο蟆?/span> 1.設(shè)計(jì)實(shí)體大多數(shù)情況下,領(lǐng)域模型的業(yè)務(wù)實(shí)體與微服務(wù)的數(shù)據(jù)庫(kù)實(shí)體是一一對(duì)應(yīng)的。 但某些領(lǐng)域模型的實(shí)體在微服務(wù)設(shè)計(jì)時(shí),可能會(huì)被設(shè)計(jì)為多個(gè)數(shù)據(jù)實(shí)體,或者實(shí)體的某些屬性被設(shè)計(jì)為值對(duì)象。 在分層架構(gòu)里,實(shí)體采用充血模型,在實(shí)體類(lèi)內(nèi)實(shí)現(xiàn)實(shí)體的全部業(yè)務(wù)邏輯。這些不同的實(shí)體都有自己的方法和業(yè)務(wù)行為,比如地址實(shí)體有新增和修改地址的方法,銀行賬號(hào)實(shí)體有新增和修改銀行賬號(hào)的方法。 實(shí)體類(lèi)放在領(lǐng)域?qū)拥?Entity 目錄結(jié)構(gòu)下。 2.找出聚合根聚合根來(lái)源于領(lǐng)域模型,聚合根是一種特殊的實(shí)體,它有自己的屬性和方法。聚合根可以實(shí)現(xiàn)聚合之間的對(duì)象引用,還可以引用聚合內(nèi)的所有實(shí)體。
聚合根類(lèi)放在代碼模型的 Entity 目錄結(jié)構(gòu)下。聚合根有自己的實(shí)現(xiàn)方法,比如生成客戶(hù)編碼,新增和修改客戶(hù)信息等方法。 3.設(shè)計(jì)值對(duì)象根據(jù)需要將某些實(shí)體的某些屬性或?qū)傩约O(shè)計(jì)為值對(duì)象。值對(duì)象類(lèi)放在代碼模型的 Entity 目錄結(jié)構(gòu)下。 在個(gè)人客戶(hù)聚合中,客戶(hù)擁有客戶(hù)證件類(lèi)型,它是以枚舉值的形式存在,所以將它設(shè)計(jì)為值對(duì)象。 有些領(lǐng)域?qū)ο罂梢栽O(shè)計(jì)為值對(duì)象,也可以設(shè)計(jì)為實(shí)體,我們需要根據(jù)具體情況來(lái)分析:
4.設(shè)計(jì)領(lǐng)域事件如果領(lǐng)域模型中領(lǐng)域事件會(huì)觸發(fā)下一步的業(yè)務(wù)操作,我們就需要設(shè)計(jì)領(lǐng)域事件。
領(lǐng)域事件實(shí)體和處理類(lèi)放在領(lǐng)域?qū)拥?Event 目錄結(jié)構(gòu)下。領(lǐng)域事件的發(fā)布和訂閱類(lèi)建議放在應(yīng)用層的 Event 目錄結(jié)構(gòu)下。 5.設(shè)計(jì)領(lǐng)域服務(wù)如果一個(gè)業(yè)務(wù)動(dòng)作或行為跨多個(gè)實(shí)體,我們就需要設(shè)計(jì)領(lǐng)域服務(wù)。 領(lǐng)域服務(wù)通過(guò)對(duì)多個(gè)實(shí)體和實(shí)體方法進(jìn)行組合,完成核心業(yè)務(wù)邏輯??梢哉J(rèn)為領(lǐng)域服務(wù)是位于實(shí)體方法之上和應(yīng)用服務(wù)之下的一層業(yè)務(wù)邏輯。 按照嚴(yán)格分層架構(gòu)層的依賴(lài)關(guān)系:
領(lǐng)域服務(wù)類(lèi)放在領(lǐng)域?qū)拥?Service 目錄結(jié)構(gòu)下。 6.設(shè)計(jì)倉(cāng)儲(chǔ)每一個(gè)聚合都有一個(gè)倉(cāng)儲(chǔ),倉(cāng)儲(chǔ)主要用來(lái)完成數(shù)據(jù)查詢(xún)和持久化操作。 倉(cāng)儲(chǔ)包括倉(cāng)儲(chǔ)的接口和倉(cāng)儲(chǔ)實(shí)現(xiàn),通過(guò)依賴(lài)倒置實(shí)現(xiàn)應(yīng)用業(yè)務(wù)邏輯與數(shù)據(jù)庫(kù)資源邏輯的解耦。 倉(cāng)儲(chǔ)代碼放在領(lǐng)域?qū)拥?Repository 目錄結(jié)構(gòu)下。 (四)代碼模型強(qiáng)調(diào)內(nèi)容第一點(diǎn):聚合之間的代碼邊界一定要清晰。聚合之間的服務(wù)調(diào)用和數(shù)據(jù)關(guān)聯(lián)應(yīng)該是盡可能的松耦合和低關(guān)聯(lián),聚合之間的服務(wù)調(diào)用應(yīng)該通過(guò)上層的應(yīng)用層組合實(shí)現(xiàn)調(diào)用,原則上不允許聚合之間直接調(diào)用領(lǐng)域服務(wù)。 這種松耦合的代碼關(guān)聯(lián),在以后業(yè)務(wù)發(fā)展和需求變更時(shí),可以很方便地實(shí)現(xiàn)業(yè)務(wù)功能和聚合代碼的重組,在微服務(wù)架構(gòu)演進(jìn)中將會(huì)起到非常重要的作用。 第二點(diǎn):你一定要有代碼分層的概念。寫(xiě)代碼時(shí)一定要搞清楚代碼的職責(zé),將它放在職責(zé)對(duì)應(yīng)的代碼目錄內(nèi)。 應(yīng)用層代碼主要完成服務(wù)組合和編排,以及聚合之間的協(xié)作,它是很薄的一層,不應(yīng)該有核心領(lǐng)域邏輯代碼。 領(lǐng)域?qū)邮菢I(yè)務(wù)的核心,領(lǐng)域模型的核心邏輯代碼一定要在領(lǐng)域?qū)訉?shí)現(xiàn)。 如果將核心領(lǐng)域邏輯代碼放到應(yīng)用層,你的基于 DDD 分層架構(gòu)模型的微服務(wù)慢慢就會(huì)演變成傳統(tǒng)的三層架構(gòu)模型了。 三、正確理解微服務(wù)的邊界微服務(wù)設(shè)計(jì)的重點(diǎn),就是看微服務(wù)設(shè)計(jì)是否能夠支持架構(gòu)長(zhǎng)期、輕松的演進(jìn)。 在事件風(fēng)暴中,我們會(huì)梳理出業(yè)務(wù)過(guò)程中的用戶(hù)操作、事件以及外部依賴(lài)關(guān)系等,根據(jù)這些要素梳理出實(shí)體等領(lǐng)域?qū)ο蟆?/p>
為了方便理解,我們將這些邊界細(xì)分為:邏輯邊界、物理邊界和代碼邊界。 (一)邏輯邊界邏輯邊界主要定義同一業(yè)務(wù)領(lǐng)域或應(yīng)用內(nèi)緊密關(guān)聯(lián)的對(duì)象所組成的不同聚類(lèi)的組合之間的邊界。 微服務(wù)內(nèi)聚合之間的邊界就是邏輯邊界。一般來(lái)說(shuō)微服務(wù)會(huì)有一個(gè)以上的聚合,在開(kāi)發(fā)過(guò)程中不同聚合的代碼隔離在不同的聚合代碼目錄中。它是一個(gè)虛擬的邊界,強(qiáng)調(diào)業(yè)務(wù)的內(nèi)聚,可根據(jù)需要變成物理邊界,也就是說(shuō)聚合也可以獨(dú)立為微服務(wù)。 微服務(wù)的架構(gòu)演進(jìn)并不是隨心所欲的,需要遵循一定的規(guī)則,這個(gè)規(guī)則就是邏輯邊界。微服務(wù)架構(gòu)演進(jìn)時(shí),在業(yè)務(wù)端以聚合為單位進(jìn)行業(yè)務(wù)能力的重組,在微服務(wù)端以聚合的代碼目錄為單位進(jìn)行微服務(wù)代碼的重組。 來(lái)看一個(gè)微服務(wù)實(shí)例,在下面這張圖中,我們可以看到微服務(wù)里包含了兩個(gè)聚合的業(yè)務(wù)邏輯,兩個(gè)聚合分別內(nèi)聚了各自不同的業(yè)務(wù)能力,聚合內(nèi)的代碼分別歸到了不同的聚合目錄下。 那隨著業(yè)務(wù)的快速發(fā)展,如果某一個(gè)微服務(wù)遇到了高性能挑戰(zhàn),需要將部分業(yè)務(wù)能力獨(dú)立出去,我們就可以以聚合為單位,將聚合代碼拆分獨(dú)立為一個(gè)新的微服務(wù),這樣就可以很容易地實(shí)現(xiàn)微服務(wù)的拆分。 另外,我們也可以對(duì)多個(gè)微服務(wù)內(nèi)有相似功能的聚合進(jìn)行功能和代碼重組,組合為新的聚合和微服務(wù),獨(dú)立為通用微服務(wù),有點(diǎn)做中臺(tái)的感覺(jué)! (二)物理邊界微服務(wù)之間的邊界是物理邊界。它強(qiáng)調(diào)微服務(wù)部署和運(yùn)行的隔離,關(guān)注微服務(wù)的服務(wù)調(diào)用、容錯(cuò)和運(yùn)行等。 物理邊界主要從部署和運(yùn)行的視角來(lái)定義微服務(wù)之間的邊界。不同微服務(wù)部署位置和運(yùn)行環(huán)境是相互物理隔離的,分別運(yùn)行在不同的進(jìn)程中。這種邊界就是微服務(wù)之間的物理邊界。 舉例: 有些項(xiàng)目團(tuán)隊(duì)在將集中式單體應(yīng)用拆分為微服務(wù)時(shí),首先進(jìn)行的往往不是建立領(lǐng)域模型,而只是按照業(yè)務(wù)功能將原來(lái)單體應(yīng)用的一個(gè)軟件包拆分成多個(gè)所謂的“微服務(wù)”軟件包,而這些“微服務(wù)”內(nèi)的代碼仍然是集中式三層架構(gòu)的模式,“微服務(wù)”內(nèi)的代碼高度耦合,邏輯邊界不清晰,這里我們暫且稱(chēng)它為“小單體微服務(wù)”。 而隨著新需求的提出和業(yè)務(wù)的發(fā)展,這些小單體微服務(wù)會(huì)慢慢膨脹起來(lái)。當(dāng)有一天你發(fā)現(xiàn)這些膨脹了的微服務(wù),有一部分業(yè)務(wù)功能需要拆分出去,或者部分功能需要與其它微服務(wù)進(jìn)行重組時(shí),你會(huì)發(fā)現(xiàn)原來(lái)這些看似清晰的微服務(wù),不知不覺(jué)已經(jīng)搖身一變,變成了臃腫油膩的大單體了,而這個(gè)大單體內(nèi)的代碼依然是高度耦合且邊界不清的。 這種單體式微服務(wù)只定義了一個(gè)維度的邊界,也就是微服務(wù)之間的物理邊界,本質(zhì)上還是單體架構(gòu)模式。微服務(wù)設(shè)計(jì)時(shí)要考慮的不僅僅只有這一個(gè)邊界,別忘了還要定義好微服務(wù)內(nèi)的邏輯邊界和代碼邊界,這樣才能得到你想要的結(jié)果。 (三)代碼邊界不同層或者聚合之間代碼目錄的邊界是代碼邊界。它強(qiáng)調(diào)的是代碼之間的隔離,方便架構(gòu)演進(jìn)時(shí)代碼的重組。 代碼邊界主要用于微服務(wù)內(nèi)的不同職能代碼之間的隔離。 微服務(wù)開(kāi)發(fā)過(guò)程中會(huì)根據(jù)代碼模型建立相應(yīng)的代碼目錄,實(shí)現(xiàn)不同功能代碼的隔離。由于領(lǐng)域模型與代碼模型的映射關(guān)系,代碼邊界直接體現(xiàn)出業(yè)務(wù)邊界。 代碼邊界可以控制代碼重組的影響范圍,避免業(yè)務(wù)和服務(wù)之間的相互影響。 微服務(wù)如果需要進(jìn)行功能重組,只需要以聚合代碼為單位進(jìn)行重組就可以了。 四、正確認(rèn)識(shí)服務(wù)和數(shù)據(jù)在微服務(wù)各層的協(xié)作(一)正確認(rèn)識(shí)服務(wù)的協(xié)作1. 服務(wù)的類(lèi)型按照分層架構(gòu)設(shè)計(jì)出來(lái)的微服務(wù),其內(nèi)部有 Facade 服務(wù)、應(yīng)用服務(wù)、領(lǐng)域服務(wù)和基礎(chǔ)服務(wù)。之前都有提到,這里可以回憶一下! 2. 服務(wù)的調(diào)用(三類(lèi)主要場(chǎng)景)微服務(wù)的服務(wù)調(diào)用包括三類(lèi)主要場(chǎng)景:微服務(wù)內(nèi)跨層服務(wù)調(diào)用,微服務(wù)之間服務(wù)調(diào)用和領(lǐng)域事件驅(qū)動(dòng)。 前端應(yīng)用調(diào)用發(fā)布在 API 網(wǎng)關(guān)上的 Facade 服務(wù),F(xiàn)acade 定向到應(yīng)用服務(wù)。應(yīng)用服務(wù)作為服務(wù)組織和編排者,它的服務(wù)調(diào)用有這樣兩種路徑:
微服務(wù)之間的應(yīng)用服務(wù)可以直接訪(fǎng)問(wèn),也可以通過(guò) API 網(wǎng)關(guān)訪(fǎng)問(wèn)。 由于跨微服務(wù)操作,在進(jìn)行數(shù)據(jù)新增和修改操作時(shí),你需關(guān)注分布式事務(wù),保證數(shù)據(jù)的一致性。 領(lǐng)域事件驅(qū)動(dòng)包括微服務(wù)內(nèi)和微服務(wù)之間的事件。
當(dāng)應(yīng)用服務(wù)業(yè)務(wù)邏輯處理完成后,如果發(fā)生領(lǐng)域事件,可調(diào)用事件發(fā)布服務(wù),完成事件發(fā)布。 當(dāng)接收到訂閱的主題數(shù)據(jù)時(shí),事件訂閱服務(wù)會(huì)調(diào)用事件處理領(lǐng)域服務(wù),完成進(jìn)一步的業(yè)務(wù)操作。 3. 服務(wù)的封裝與組合微服務(wù)的服務(wù)是從領(lǐng)域?qū)又鸺?jí)向上封裝、組合和暴露的。基本如下圖體現(xiàn): (二)正確認(rèn)識(shí)服務(wù)數(shù)據(jù)的協(xié)作在 DDD 中有很多的數(shù)據(jù)對(duì)象,這些對(duì)象分布在不同的層里。它們?cè)诓煌碾A段有不同的形態(tài):
微服務(wù)各層數(shù)據(jù)對(duì)象的職責(zé)和轉(zhuǎn)換過(guò)程如下: 1.基礎(chǔ)層數(shù)據(jù)協(xié)作基礎(chǔ)層的主要對(duì)象是 PO 對(duì)象。 我們需要先建立 DO 和 PO 的映射關(guān)系:
大多數(shù)情況下 PO 和 DO 是一一對(duì)應(yīng)的。但也有 DO 和 PO 多對(duì)多的情況,在 DO 和 PO 數(shù)據(jù)轉(zhuǎn)換時(shí),需要進(jìn)行數(shù)據(jù)重組。 2.領(lǐng)域?qū)訑?shù)據(jù)協(xié)作領(lǐng)域?qū)拥闹饕獙?duì)象是 DO 對(duì)象。 DO 是實(shí)體和值對(duì)象的數(shù)據(jù)和業(yè)務(wù)行為載體,承載著基礎(chǔ)的核心業(yè)務(wù)邏輯。 通過(guò) DO 和 PO 轉(zhuǎn)換,我們可以完成數(shù)據(jù)持久化和初始化。 3.應(yīng)用層數(shù)據(jù)協(xié)作應(yīng)用層的主要對(duì)象是 DO 對(duì)象。 如果需要調(diào)用其它微服務(wù)的應(yīng)用服務(wù),DO 會(huì)轉(zhuǎn)換為 DTO,完成跨微服務(wù)的數(shù)據(jù)組裝和傳輸。 用戶(hù)接口層先完成 DTO 到 DO 的轉(zhuǎn)換,然后應(yīng)用服務(wù)接收 DO 進(jìn)行業(yè)務(wù)處理。如果 DTO 與 DO 是一對(duì)多的關(guān)系,這時(shí)就需要進(jìn)行 DO 數(shù)據(jù)重組。 4.用戶(hù)接口層數(shù)據(jù)協(xié)作用戶(hù)接口層會(huì)完成 DO 和 DTO 的互轉(zhuǎn),完成微服務(wù)與前端應(yīng)用數(shù)據(jù)交互及轉(zhuǎn)換。 Facade 服務(wù)會(huì)對(duì)多個(gè) DO 對(duì)象進(jìn)行組裝,轉(zhuǎn)換為 DTO 對(duì)象,向前端應(yīng)用完成數(shù)據(jù)轉(zhuǎn)換和傳輸。 5.前端應(yīng)用數(shù)據(jù)協(xié)作前端應(yīng)用主要是 VO 對(duì)象。 展現(xiàn)層使用 VO 進(jìn)行界面展示,通過(guò)用戶(hù)接口層與應(yīng)用層采用 DTO 對(duì)象進(jìn)行數(shù)據(jù)交互。 參考書(shū)籍、文獻(xiàn)和資料1.極客時(shí)間課程《DDD實(shí)戰(zhàn)》,歐創(chuàng)新,2019. 2.鄭天民. 微服務(wù)設(shè)計(jì)原理與架構(gòu). 北京:人民郵電出版社,2018. 3.陳超、秦金衛(wèi)、張逸等. 高可用可伸縮微服務(wù)架構(gòu). 電子工業(yè)出版社. 2019. 4.Eric Evans. 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)-軟件核心復(fù)雜性應(yīng)對(duì)之道。 人民郵電出版社. 2018. |
|