博客:https://bugstack.cn
本文來(lái)自于小傅哥新編寫的《Java簡(jiǎn)明教程》系列內(nèi)容,本教程意在于通過(guò)簡(jiǎn)單、明了、清晰的成體系內(nèi)容,教會(huì)Java學(xué)習(xí)伙伴,可以在學(xué)習(xí)后能進(jìn)行Java項(xiàng)目開發(fā)。
今天要分享的是 MVC 和 DDD 的架構(gòu)本質(zhì),通過(guò)由淺入深的介紹講解和視頻帶著手把手操作創(chuàng)建工程架構(gòu)。讓無(wú)論是學(xué)習(xí) MVC 的小白碼農(nóng)還是希望了解更多關(guān)于 DDD 內(nèi)容的老白碼農(nóng),都可以學(xué)習(xí)到一點(diǎn)自己需要的內(nèi)容。
一、MVC 架構(gòu)
如果我們嘗試把編程的復(fù)雜架構(gòu)縮小到最容易理解的程度,那么編程開發(fā)其實(shí)只做3件事:”定義屬性
、創(chuàng)建方法
、調(diào)用展示
“。但因?yàn)橥愃璧膬?nèi)容較多,如一系列的屬性,一堆的方法實(shí)現(xiàn),一組的接口封裝,那么就需要合理的把這些內(nèi)容分配到不同的層次中去實(shí)現(xiàn),因此有了分層架構(gòu)的設(shè)計(jì)。
那么本文小傅哥會(huì)向大家介紹一套MVC架構(gòu)的分層設(shè)計(jì)以及如何創(chuàng)建使用,并提供相應(yīng)的簡(jiǎn)單的案例。你可以復(fù)制這套架構(gòu)在自己的場(chǎng)景中使用,也更能方便編程的小白可以更快的上手開發(fā)。
注意:此套MVC架構(gòu)模型適合提供HTTP服務(wù)的工程架構(gòu),適合簡(jiǎn)單的小場(chǎng)景開發(fā)使用。特點(diǎn);輕便、簡(jiǎn)單、學(xué)習(xí)成本低。
1. 編程三步
如果說(shuō)你是一個(gè)特別小的玩具項(xiàng)目
,你甚至可以把編程的3步寫到一個(gè)類里。但因?yàn)槟阕龅氖钦?jīng)項(xiàng)目,你的各種類;對(duì)象類、庫(kù)表類、方法類,就會(huì)成群結(jié)隊(duì)的來(lái)。如果你想把這些成群結(jié)隊(duì)的類的內(nèi)容,都寫到一個(gè)類里去,那么就是幾萬(wàn)行的代碼了。—— 當(dāng)然你也可以吹牛逼,你一個(gè)人做過(guò)一個(gè)項(xiàng)目,這項(xiàng)目大到啥程度呢。就是有一個(gè)類里有上萬(wàn)行代碼。
所以,為了不至于讓一個(gè)類撐到爆,需要把黃色的對(duì)象、綠色的方法、紅色的接口,都分配到不同的包結(jié)構(gòu)下。這就是你編碼人生中所接觸到的第一個(gè)解耦操作。
2. 分層框架
MVC 是一種非常常見(jiàn)且常用的分層架構(gòu),主要包括;M - mode 對(duì)象層,封裝到 domain 里。V - view 展示層,但因?yàn)槟壳岸际乔昂蠖朔蛛x的項(xiàng)目,幾乎不會(huì)在后端項(xiàng)目里寫 JSP 文件了。C - Controller 控制層,對(duì)外提供接口實(shí)現(xiàn)類。DAO 算是單獨(dú)拿出來(lái)用戶處理數(shù)據(jù)庫(kù)操作的層。
- 如圖,在 MVC 的分層架構(gòu)下。我們編程3步的所需各類對(duì)象、方法、接口,都分配到 MVC 的各個(gè)層次中去。因?yàn)檫@樣分層以后,就可以很清晰明了的知道各個(gè)層都在做什么內(nèi)容,也更加方便后續(xù)的維護(hù)和迭代。對(duì)于一個(gè)真正的項(xiàng)目來(lái)說(shuō),是沒(méi)有一錘子買賣的,最開始的開發(fā)遠(yuǎn)不是成本所在。最大的開發(fā)成本是后期的維護(hù)和迭代。而架構(gòu)設(shè)計(jì)的意義更多的就是在解決系統(tǒng)的反復(fù)的維護(hù)和迭代時(shí),如何降低成本,這也是架構(gòu)分層的意義所在。
3. 調(diào)用流程
接下來(lái)我們?cè)倏聪乱惶?MVC 架構(gòu)中各個(gè)模塊在調(diào)用時(shí)的串聯(lián)關(guān)系;
- 以用戶發(fā)起 HTTP 請(qǐng)求開始,Controller 在接收到請(qǐng)求后,調(diào)用由 Spring 注入到類里的 Service 方法,進(jìn)入 Service 方法后有些邏輯會(huì)走數(shù)據(jù)庫(kù),有些邏輯是直接內(nèi)部自己處理后就直接返回給 Controller 了。最后由 Controller 封裝結(jié)果返回給 HTTP 響應(yīng)。同時(shí)我們也可以看到各個(gè)對(duì)象在這些請(qǐng)求間的一個(gè)作用,如;請(qǐng)求對(duì)象、庫(kù)表對(duì)象、返回對(duì)象。
4. 架構(gòu)源碼
4.1 環(huán)境
-
- JDK 1.8Maven 3.8.6 - 下載安裝maven后,本地記得配置阿里云鏡像,方便快速拉取jar包。源碼中
docs/maven/settings.xml
- 有阿里云鏡像地址。SpringBoot 2.7.2MySQL 5.7 - 如果你使用 8.0 記得更改 pom.xml 中的 mysql 引用
4.2 架構(gòu)
-
- 源碼:https://gitcode.net/KnowledgePlanet/road-map/xfg-frame-mvc
-
-
- 樹形:
安裝 brew install tree
IntelliJ IDEA Terminal 使用 tree
-
.
├──?docs
│???└──?mvc.drawio?-?架構(gòu)文檔
├──?pom.xml
├──?src
│???├──?main
│???│???├──?java
│???│???│???└──?cn
│???│???│???????└──?bugstack
│???│???│???????????└──?xfg
│???│???│???????????????└──?frame
│???│???│???????????????????├──?Application.java
│???│???│???????????????????├──?common
│???│???│???????????????????│???├──?Constants.java
│???│???│???????????????????│???└──?Result.java
│???│???│???????????????????├──?controller
│???│???│???????????????????│???└──?UserController.java
│???│???│???????????????????├──?dao
│???│???│???????????????????│???└──?IUserDao.java
│???│???│???????????????????├──?domain
│???│???│???????????????????│???├──?po
│???│???│???????????????????│???│???└──?User.java
│???│???│???????????????????│???├──?req
│???│???│???????????????????│???│???└──?UserReq.java
│???│???│???????????????????│???├──?res
│???│???│???????????????????│???│???└──?UserRes.java
│???│???│???????????????????│???└──?vo
│???│???│???????????????????│???????└──?UserInfo.java
│???│???│???????????????????└──?service
│???│???│???????????????????????├──?IUserService.java
│???│???│???????????????????????└──?impl
│???│???│???????????????????????????└──?UserServiceImpl.java
│???│???└──?resources
│???│???????├──?application.yml
│???│???????└──?mybatis
│???│???????????├──?config
│???│???????????│???└──?mybatis-config.xml
│???│???????????└──?mapper
│???│???????????????└──?User_Mapper.xml
│???└──?test
│???????└──?java
│???????????└──?cn
│???????????????└──?bugstack
│???????????????????└──?xfg
│???????????????????????└──?frame
│???????????????????????????└──?test
│???????????????????????????????└──?ApiTest.java
└──?road-map.sql
以上是整個(gè)工程架構(gòu)的 tree 樹形圖。整個(gè)工程由 SpringBoot 驅(qū)動(dòng)。
- Application.java 是啟動(dòng)程序的 SpringBoot 應(yīng)用common 是額外添加的一個(gè)層,用于定義通用的類controller 控制層,提供接口實(shí)現(xiàn)。dao 數(shù)據(jù)庫(kù)操作層domain 對(duì)象定義層service 服務(wù)實(shí)現(xiàn)層
5. 測(cè)試驗(yàn)證
- 首先;整個(gè)工程由 SpringBoot 驅(qū)動(dòng),提供了 road-map.sql 測(cè)試 SQL 庫(kù)表語(yǔ)句。你可以在自己的本地mysql上進(jìn)行執(zhí)行。它會(huì)創(chuàng)建庫(kù)表。之后;在 application.yml 配置數(shù)據(jù)庫(kù)鏈接信息。之后就可以打開 ApiTest 進(jìn)行測(cè)試了。你可以點(diǎn)擊 Application 類的綠色箭頭啟動(dòng)工程,使用 UserController 類提供接口的方式調(diào)用程序;http://localhost:8089/queryUserInfo
- 如果你正常獲取了這樣的結(jié)果信息,那么說(shuō)明你已經(jīng)啟動(dòng)成功。接下來(lái)就可以對(duì)照著MVC的結(jié)構(gòu)進(jìn)行學(xué)習(xí),以及使用這樣的工程結(jié)構(gòu)開發(fā)自己的項(xiàng)目。
二、DDD 架構(gòu)
從最早接觸 DDD 架構(gòu),到后來(lái)用 DDD 架構(gòu)不斷的承接項(xiàng)目開發(fā),一次次在項(xiàng)目開發(fā)中的經(jīng)驗(yàn)積累。對(duì) DDD 有了不少的理解。DDD 是一種思想,落地的形態(tài)和結(jié)構(gòu)會(huì)有不同的方式,甚至在編碼上也會(huì)有風(fēng)格的差異。但終期目標(biāo)就一個(gè);”提供代碼的可維護(hù)性,降低迭代開發(fā)成本。“也是康威定律所述:”任何組織在設(shè)計(jì)一套系統(tǒng)時(shí),所交付的設(shè)計(jì)方案在結(jié)構(gòu)上都與該組織的溝通結(jié)構(gòu)保持一致?!?/p>
但 DDD 與 MVC 相比的概率較多,貿(mào)然用理論驅(qū)動(dòng)代碼開發(fā),會(huì)讓整個(gè)工程變得非常混亂,甚至可能雖然是用的 DDD 但最后寫出來(lái)了一片四不像的 MVC 代碼。所以對(duì)于程序員來(lái)說(shuō),先能上手一個(gè)工程,在從工程了解理論會(huì)更加容易。為此小傅哥想以此文,通過(guò)實(shí)戰(zhàn)編碼的方式向大家分享 DDD 架構(gòu),并能讓大家上手的 DDD 架構(gòu)。
1. 問(wèn)題碰撞
你用 MVC 寫代碼,遇到過(guò)最大的問(wèn)題是什么?
??
簡(jiǎn)單、容易、好理解,是 MVC 架構(gòu)的特點(diǎn),但也正因?yàn)楹?jiǎn)單的分層邏輯,在適配較復(fù)雜的場(chǎng)景并且需要長(zhǎng)周期的維護(hù)時(shí),代碼的迭代成本就會(huì)越來(lái)越高。如圖;
-
- 如果你接觸過(guò)較大型且已經(jīng)長(zhǎng)期維護(hù)項(xiàng)目的 MVC 架構(gòu),你就會(huì)發(fā)現(xiàn)這里的 DAO、PO、VO 對(duì)象,在 Service 層相互調(diào)用。那么長(zhǎng)期開發(fā)后,就導(dǎo)致了各個(gè) PO 里的屬性字段數(shù)量都被撐的特別大。這樣的開發(fā)方式,將”狀態(tài)”、
“行為“
- 分離到不同的對(duì)象中,代碼的意圖漸漸模糊,膨脹、臃腫和不穩(wěn)定的架構(gòu),讓迭代成本增加。而 DDD 架構(gòu)首先以解決此類問(wèn)題為主,將各個(gè)屬于自己領(lǐng)域范圍內(nèi)的行為和邏輯封裝到自己的領(lǐng)域包下處理。這也是 DDD 架構(gòu)設(shè)計(jì)的精髓之一。它希望在分治層面合理切割問(wèn)題空間為更小規(guī)模的若干子問(wèn)題,而問(wèn)題越小就容易被理解和處理,做到高內(nèi)聚低耦合。這也是康威定律所提到的,解決復(fù)雜場(chǎng)景的設(shè)計(jì)主要分為:分治、抽象和知識(shí)。
2. 簡(jiǎn)化理解
在給大家講解 MVC 架構(gòu)的時(shí)候,小傅哥提到了一個(gè)簡(jiǎn)單的開發(fā)模型。開發(fā)代碼可以理解為:“定義屬性 -> 創(chuàng)建方法 -> 調(diào)用展示”
但這個(gè)模型結(jié)構(gòu)過(guò)于簡(jiǎn)單,不太適合運(yùn)用了各類分布式技術(shù)棧以及更多邏輯的 DDD 架構(gòu)。所以在 DDD 這里,我們把開發(fā)代碼可以抽象為:“觸發(fā) -> 函數(shù) -> 連接”
如圖;
-
- DDD 架構(gòu)常用于微服務(wù)場(chǎng)景,因此也一個(gè)系統(tǒng)的調(diào)用方式就不只是 HTTP 還包括;
RPC 遠(yuǎn)程
、
MQ 消息
、
TASK 任務(wù)
,因此這些種方式都可以理解為觸發(fā)。通過(guò)觸發(fā)調(diào)用函數(shù)方法,我們這里可以把各個(gè)服務(wù)都當(dāng)成一個(gè)函數(shù)方法來(lái)看。而函數(shù)方法通過(guò)連接,調(diào)用到其他的接口、數(shù)據(jù)庫(kù)、緩存來(lái)完成函數(shù)邏輯。
接下來(lái),小傅哥在帶著大家把這些所需的模塊,拆分到對(duì)應(yīng)的DDD系統(tǒng)架構(gòu)中。
3. 架構(gòu)分層
如下是 DDD 架構(gòu)的一種分層結(jié)構(gòu),也可以有其他種方式,核心的重點(diǎn)在于適合你所在場(chǎng)景的業(yè)務(wù)開發(fā)。以下的分層結(jié)構(gòu),是小傅哥在使用 DDD 架構(gòu)多種的方式開發(fā)代碼后,做了簡(jiǎn)化和處理的。右側(cè)的連線是各個(gè)模塊的依賴關(guān)系。接下來(lái)小傅哥就給大家做一下模塊的介紹。
- 接口定義 - xfg-frame-api:因?yàn)槲⒎?wù)中引用的 RPC 需要對(duì)外提供接口的描述信息,也就是調(diào)用方在使用的時(shí)候,需要引入 Jar 包,讓調(diào)用方好能依賴接口的定義做代理。應(yīng)用封裝 - xfg-frame-app:這是應(yīng)用啟動(dòng)和配置的一層,如一些 aop 切面或者 config 配置,以及打包鏡像都是在這一層處理。你可以把它理解為專門為了啟動(dòng)服務(wù)而存在的。領(lǐng)域封裝 - xfg-frame-domain:領(lǐng)域模型服務(wù),是一個(gè)非常重要的模塊。無(wú)論怎么做DDD的分層架構(gòu),domain 都是肯定存在的。在一層中會(huì)有一個(gè)個(gè)細(xì)分的領(lǐng)域服務(wù),在每個(gè)服務(wù)包中會(huì)有【模型、倉(cāng)庫(kù)、服務(wù)】這樣3部分。倉(cāng)儲(chǔ)服務(wù) - xfg-frame-infrastructure:基礎(chǔ)層依賴于 domain 領(lǐng)域?qū)?,因?yàn)樵?domain 層定義了倉(cāng)儲(chǔ)接口需要在基礎(chǔ)層實(shí)現(xiàn)。這是依賴倒置的一種設(shè)計(jì)方式。領(lǐng)域封裝 - xfg-frame-trigger:觸發(fā)器層,一般也被叫做 adapter 適配器層。用于提供接口實(shí)現(xiàn)、消息接收、任務(wù)執(zhí)行等。所以對(duì)于這樣的操作,小傅哥把它叫做觸發(fā)器層。類型定義 - xfg-frame-types:通用類型定義層,在我們的系統(tǒng)開發(fā)中,會(huì)有很多類型的定義,包括;基本的 Response、Constants 和枚舉。它會(huì)被其他的層進(jìn)行引用使用。領(lǐng)域編排【可選】 - xfg-frame-case:領(lǐng)域編排層,一般對(duì)于較大且復(fù)雜的的項(xiàng)目,為了更好的防腐和提供通用的服務(wù),一般會(huì)添加 case/application 層,用于對(duì) domain 領(lǐng)域的邏輯進(jìn)行封裝組合處理。
4. 架構(gòu)源碼
4.1 環(huán)境
- JDK 1.8Maven 3.8.6SpringBoot 2.7.2MySQL 5.7 - 如果你使用 8.0 記得更改 pom.xml 中的 mysql 引用
4.2 架構(gòu)
-
- 源碼:https://gitcode.net/KnowledgePlanet/road-map/xfg-frame-ddd
-
-
- 樹形:
安裝 brew install tree
IntelliJ IDEA Terminal 使用 tree
-
.
├──?README.md
├──?docs
│???├──?dev-ops
│???│???├──?environment
│???│???│???└──?environment-docker-compose.yml
│???│???├──?siege.sh
│???│???└──?skywalking
│???│???????└──?skywalking-docker-compose.yml
│???├──?doc.md
│???├──?sql
│???│???└──?road-map.sql
│???└──?xfg-frame-ddd.drawio
├──?pom.xml
├──?xfg-frame-api
│???├──?pom.xml
│???├──?src
│???│???└──?main
│???│???????└──?java
│???│???????????└──?cn
│???│???????????????└──?bugstack
│???│???????????????????└──?xfg
│???│???????????????????????└──?frame
│???│???????????????????????????└──?api
│???│???????????????????????????????├──?IAccountService.java
│???│???????????????????????????????├──?IRuleService.java
│???│???????????????????????????????├──?model
│???│???????????????????????????????│???├──?request
│???│???????????????????????????????│???│???└──?DecisionMatterRequest.java
│???│???????????????????????????????│???└──?response
│???│???????????????????????????????│???????└──?DecisionMatterResponse.java
│???│???????????????????????????????└──?package-info.java
│???└──?xfg-frame-api.iml
├──?xfg-frame-app
│???├──?Dockerfile
│???├──?build.sh
│???├──?pom.xml
│???├──?src
│???│???├──?main
│???│???│???├──?bin
│???│???│???│???├──?start.sh
│???│???│???│???└──?stop.sh
│???│???│???├──?java
│???│???│???│???└──?cn
│???│???│???│???????└──?bugstack
│???│???│???│???????????└──?xfg
│???│???│???│???????????????└──?frame
│???│???│???│???????????????????├──?Application.java
│???│???│???│???????????????????├──?aop
│???│???│???│???????????????????│???├──?RateLimiterAop.java
│???│???│???│???????????????????│???└──?package-info.java
│???│???│???│???????????????????└──?config
│???│???│???│???????????????????????├──?RateLimiterAopConfig.java
│???│???│???│???????????????????????├──?RateLimiterAopConfigProperties.java
│???│???│???│???????????????????????├──?ThreadPoolConfig.java
│???│???│???│???????????????????????├──?ThreadPoolConfigProperties.java
│???│???│???│???????????????????????└──?package-info.java
│???│???│???└──?resources
│???│???│???????├──?application-dev.yml
│???│???│???????├──?application-prod.yml
│???│???│???????├──?application-test.yml
│???│???│???????├──?application.yml
│???│???│???????├──?logback-spring.xml
│???│???│???????└──?mybatis
│???│???│???????????├──?config
│???│???│???????????│???└──?mybatis-config.xml
│???│???│???????????└──?mapper
│???│???│???????????????├──?RuleTreeNodeLine_Mapper.xml
│???│???│???????????????├──?RuleTreeNode_Mapper.xml
│???│???│???????????????└──?RuleTree_Mapper.xml
│???│???└──?test
│???│???????└──?java
│???│???????????└──?cn
│???│???????????????└──?bugstack
│???│???????????????????└──?xfg
│???│???????????????????????└──?frame
│???│???????????????????????????└──?test
│???│???????????????????????????????└──?ApiTest.java
│???└──?xfg-frame-app.iml
├──?xfg-frame-ddd.iml
├──?xfg-frame-domain
│???├──?pom.xml
│???├──?src
│???│???└──?main
│???│???????└──?java
│???│???????????└──?cn
│???│???????????????└──?bugstack
│???│???????????????????└──?xfg
│???│???????????????????????└──?frame
│???│???????????????????????????└──?domain
│???│???????????????????????????????├──?order
│???│???????????????????????????????│???├──?model
│???│???????????????????????????????│???│???├──?aggregates
│???│???????????????????????????????│???│???│???└──?OrderAggregate.java
│???│???????????????????????????????│???│???├──?entity
│???│???????????????????????????????│???│???│???├──?OrderItemEntity.java
│???│???????????????????????????????│???│???│???└──?ProductEntity.java
│???│???????????????????????????????│???│???├──?package-info.java
│???│???????????????????????????????│???│???└──?valobj
│???│???????????????????????????????│???│???????├──?OrderIdVO.java
│???│???????????????????????????????│???│???????├──?ProductDescriptionVO.java
│???│???????????????????????????????│???│???????└──?ProductNameVO.java
│???│???????????????????????????????│???├──?repository
│???│???????????????????????????????│???│???├──?IOrderRepository.java
│???│???????????????????????????????│???│???└──?package-info.java
│???│???????????????????????????????│???└──?service
│???│???????????????????????????????│???????├──?OrderService.java
│???│???????????????????????????????│???????└──?package-info.java
│???│???????????????????????????????├──?rule
│???│???????????????????????????????│???├──?model
│???│???????????????????????????????│???│???├──?aggregates
│???│???????????????????????????????│???│???│???└──?TreeRuleAggregate.java
│???│???????????????????????????????│???│???├──?entity
│???│???????????????????????????????│???│???│???├──?DecisionMatterEntity.java
│???│???????????????????????????????│???│???│???└──?EngineResultEntity.java
│???│???????????????????????????????│???│???├──?package-info.java
│???│???????????????????????????????│???│???└──?valobj
│???│???????????????????????????????│???│???????├──?TreeNodeLineVO.java
│???│???????????????????????????????│???│???????├──?TreeNodeVO.java
│???│???????????????????????????????│???│???????└──?TreeRootVO.java
│???│???????????????????????????????│???├──?repository
│???│???????????????????????????????│???│???├──?IRuleRepository.java
│???│???????????????????????????????│???│???└──?package-info.java
│???│???????????????????????????????│???└──?service
│???│???????????????????????????????│???????├──?engine
│???│???????????????????????????????│???????│???├──?EngineBase.java
│???│???????????????????????????????│???????│???├──?EngineConfig.java
│???│???????????????????????????????│???????│???├──?EngineFilter.java
│???│???????????????????????????????│???????│???└──?impl
│???│???????????????????????????????│???????│???????└──?RuleEngineHandle.java
│???│???????????????????????????????│???????├──?logic
│???│???????????????????????????????│???????│???├──?BaseLogic.java
│???│???????????????????????????????│???????│???├──?LogicFilter.java
│???│???????????????????????????????│???????│???└──?impl
│???│???????????????????????????????│???????│???????├──?UserAgeFilter.java
│???│???????????????????????????????│???????│???????└──?UserGenderFilter.java
│???│???????????????????????????????│???????└──?package-info.java
│???│???????????????????????????????└──?user
│???│???????????????????????????????????├──?model
│???│???????????????????????????????????│???└──?valobj
│???│???????????????????????????????????│???????└──?UserVO.java
│???│???????????????????????????????????├──?repository
│???│???????????????????????????????????│???└──?IUserRepository.java
│???│???????????????????????????????????└──?service
│???│???????????????????????????????????????├──?UserService.java
│???│???????????????????????????????????????└──?impl
│???│???????????????????????????????????????????└──?UserServiceImpl.java
│???└──?xfg-frame-domain.iml
├──?xfg-frame-infrastructure
│???├──?pom.xml
│???├──?src
│???│???└──?main
│???│???????└──?java
│???│???????????└──?cn
│???│???????????????└──?bugstack
│???│???????????????????└──?xfg
│???│???????????????????????└──?frame
│???│???????????????????????????└──?infrastructure
│???│???????????????????????????????├──?dao
│???│???????????????????????????????│???├──?IUserDao.java
│???│???????????????????????????????│???├──?RuleTreeDao.java
│???│???????????????????????????????│???├──?RuleTreeNodeDao.java
│???│???????????????????????????????│???└──?RuleTreeNodeLineDao.java
│???│???????????????????????????????├──?package-info.java
│???│???????????????????????????????├──?po
│???│???????????????????????????????│???├──?RuleTreeNodeLineVO.java
│???│???????????????????????????????│???├──?RuleTreeNodeVO.java
│???│???????????????????????????????│???├──?RuleTreeVO.java
│???│???????????????????????????????│???└──?UserPO.java
│???│???????????????????????????????└──?repository
│???│???????????????????????????????????├──?RuleRepository.java
│???│???????????????????????????????????└──?UserRepository.java
│???└──?xfg-frame-infrastructure.iml
├──?xfg-frame-trigger
│???├──?pom.xml
│???├──?src
│???│???└──?main
│???│???????└──?java
│???│???????????└──?cn
│???│???????????????└──?bugstack
│???│???????????????????└──?xfg
│???│???????????????????????└──?frame
│???│???????????????????????????└──?trigger
│???│???????????????????????????????├──?http
│???│???????????????????????????????│???├──?Controller.java
│???│???????????????????????????????│???└──?package-info.java
│???│???????????????????????????????├──?mq
│???│???????????????????????????????│???└──?package-info.java
│???│???????????????????????????????├──?rpc
│???│???????????????????????????????│???├──?AccountService.java
│???│???????????????????????????????│???├──?RuleService.java
│???│???????????????????????????????│???└──?package-info.java
│???│???????????????????????????????└──?task
│???│???????????????????????????????????└──?package-info.java
│???└──?xfg-frame-trigger.iml
└──?xfg-frame-types
????├──?pom.xml
????├──?src
????│???└──?main
????│???????└──?java
????│???????????└──?cn
????│???????????????└──?bugstack
????│???????????????????└──?xfg
????│???????????????????????└──?frame
????│???????????????????????????└──?types
????│???????????????????????????????├──?Constants.java
????│???????????????????????????????├──?Response.java
????│???????????????????????????????└──?package-info.java
????└──?xfg-frame-types.iml
以上是整個(gè)工程架構(gòu)的 tree 樹形圖。整個(gè)工程由 ?xfg-frame-app 模的 SpringBoot 驅(qū)動(dòng)。這里小傅哥在 domain 領(lǐng)域模型下提供了 order、rule、user 三個(gè)領(lǐng)域模塊。并在每個(gè)模塊下提供了對(duì)應(yīng)的測(cè)試內(nèi)容。這塊是整個(gè)模型的重點(diǎn),其他模塊都可以通過(guò)測(cè)試看到這里的調(diào)用過(guò)程。
4.3 領(lǐng)域
一個(gè)領(lǐng)域模型中包含3個(gè)部分;model、repository、service 三部分;
- model 對(duì)象的定義repository 倉(cāng)儲(chǔ)的定義service 服務(wù)實(shí)現(xiàn)
以上3個(gè)模塊,一般也是大家在使用 DDD 時(shí)候最不容易理解的分層。比如 model 里還分為;valobj - 值對(duì)象、entity 實(shí)體對(duì)象、aggregates 聚合對(duì)象;
- 值對(duì)象:表示沒(méi)有唯一標(biāo)識(shí)的業(yè)務(wù)實(shí)體,例如商品的名稱、描述、價(jià)格等。實(shí)體對(duì)象:表示具有唯一標(biāo)識(shí)的業(yè)務(wù)實(shí)體,例如訂單、商品、用戶等;聚合對(duì)象:是一組相關(guān)的實(shí)體對(duì)象的根,用于保證實(shí)體對(duì)象之間的一致性和完整性;
關(guān)于model中各個(gè)對(duì)象的拆分,尤其是聚合的定義,會(huì)牽引著整個(gè)模型的設(shè)計(jì)。當(dāng)然你可以在初期使用 DDD 的時(shí)候不用過(guò)分在意領(lǐng)域模型的設(shè)計(jì),可以把整個(gè) domain 下的一個(gè)個(gè)包當(dāng)做充血模型結(jié)構(gòu),這樣編寫出來(lái)的代碼也是非常適合維護(hù)的。
4.4 環(huán)境(開發(fā)/測(cè)試/上線)
源碼:xfg-frame-ddd/pom.xml
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<profileActive>dev</profileActive>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<profileActive>test</profileActive>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<profileActive>prod</profileActive>
</properties>
</profile>
- 定義環(huán)境;開發(fā)、測(cè)試、上線。
源碼:xfg-frame-app/application.yml
spring:
??config:
????name:?xfg-frame
??profiles:
????active:?dev?#?dev、test、prod
-
- 除了 pom 的配置,還需要在 application.yml 中指定環(huán)境。這樣就可以對(duì)應(yīng)的加載到;
application-dev.yml
-
- 、
application-prod.yml
-
- 、
application-test.yml
- 這樣就可以很方便的加載對(duì)應(yīng)的配置信息了。尤其是各個(gè)場(chǎng)景中切換會(huì)更加方便。
4.5 切面
一個(gè)工程開發(fā)中,有時(shí)候可能會(huì)有很多的統(tǒng)一切面和啟動(dòng)配置的處理,這些內(nèi)容都可以在 xfg-frame-app 完成。
源碼:cn.bugstack.xfg.frame.aop.RateLimiterAop
@Slf4j
@Aspect
public?class?RateLimiterAop?{
????private?final?long?timeout;
????private?final?double?permitsPerSecond;
????private?final?RateLimiter?limiter;
????public?RateLimiterAop(double?permitsPerSecond,?long?timeout)?{
????????this.permitsPerSecond?=?permitsPerSecond;
????????this.timeout?=?timeout;
????????this.limiter?=?RateLimiter.create(permitsPerSecond);
????}
????@Pointcut("execution(*?cn.bugstack.xfg.frame.trigger..*.*(..))")
????public?void?pointCut()?{
????}
????@Around(value?=?"pointCut()",?argNames?=?"jp")
????public?Object?around(ProceedingJoinPoint?jp)?throws?Throwable?{
????????boolean?tryAcquire?=?limiter.tryAcquire(timeout,?TimeUnit.MILLISECONDS);
????????if?(!tryAcquire)?{
????????????Method?method?=?getMethod(jp);
????????????log.warn("方法?{}.{}?請(qǐng)求已被限流,超過(guò)限流配置[{}/秒]",?method.getDeclaringClass().getCanonicalName(),?method.getName(),?permitsPerSecond);
????????????return?Response.<Object>builder()
????????????????????.code(Constants.ResponseCode.RATE_LIMITER.getCode())
????????????????????.info(Constants.ResponseCode.RATE_LIMITER.getInfo())
????????????????????.build();
????????}
????????return?jp.proceed();
????}
????private?Method?getMethod(JoinPoint?jp)?throws?NoSuchMethodException?{
????????Signature?sig?=?jp.getSignature();
????????MethodSignature?methodSignature?=?(MethodSignature)?sig;
????????return?jp.getTarget().getClass().getMethod(methodSignature.getName(),?methodSignature.getParameterTypes());
????}
}
使用
#?限流配置
rate-limiter:
??permits-per-second:?1
??timeout:?5
- 這樣你所有的通用配置,又和業(yè)務(wù)沒(méi)有太大的關(guān)系的,就可以直接寫到這里了?!?具體可以參考代碼。
5. 測(cè)試驗(yàn)證
- 首先;整個(gè)工程由 SpringBoot 驅(qū)動(dòng),提供了 road-map.sql 測(cè)試 SQL 庫(kù)表語(yǔ)句。你可以在自己的本地mysql上進(jìn)行執(zhí)行。它會(huì)創(chuàng)建庫(kù)表。之后;在 application.yml 配置數(shù)據(jù)庫(kù)鏈接信息。之后就可以打開 ApiTest 進(jìn)行測(cè)試了。你可以點(diǎn)擊 Application 類的綠色箭頭啟動(dòng)工程,使用觸發(fā)器里的接口調(diào)用測(cè)試,或者單元測(cè)試RPC接口,小傅哥也提供了泛化調(diào)用的方式。
- 如果你正常獲取了這樣的結(jié)果信息,那么說(shuō)明你已經(jīng)啟動(dòng)成功。接下來(lái)就可以對(duì)照著DDD的結(jié)構(gòu)進(jìn)行學(xué)習(xí),以及使用這樣的工程結(jié)構(gòu)開發(fā)自己的項(xiàng)目。
三、實(shí)戰(zhàn) - DDD 項(xiàng)目
紙上得來(lái)終覺(jué)淺,碼農(nóng)學(xué)習(xí)要實(shí)戰(zhàn)!
無(wú)論是 MVC 還是各類 DDD 所呈現(xiàn)的架構(gòu),還是需要看到實(shí)際的代碼,以及參與實(shí)戰(zhàn)開發(fā)才能更好的吸收。否則都是理論仍舊難以讓人下手。
所以小傅哥為大家準(zhǔn)備了一些學(xué)習(xí)項(xiàng)目,這些項(xiàng)目都是非常具有架構(gòu)思維以及設(shè)計(jì)模式的應(yīng)用級(jí)實(shí)戰(zhàn)項(xiàng)目架構(gòu)設(shè)計(jì)和落地。對(duì)于一些小白來(lái)說(shuō),如果能早早的接觸到這樣的項(xiàng)目,就相當(dāng)于是提前進(jìn)入企業(yè)實(shí)習(xí)了。可以極大的提到編程思維以及開發(fā)能力。
這些項(xiàng)目包括:《Lottery 抽獎(jiǎng)系統(tǒng) - 基于領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的四層架構(gòu)實(shí)踐》、《API網(wǎng)關(guān):中間件設(shè)計(jì)和落地》、《ChatGPT 微服務(wù)應(yīng)用體系搭建》、《IM 仿微信》、《SpringBoot Starter 中間件設(shè)計(jì)和落地》等。這里小傅哥只列3張圖,你就知道有多牛皮了!
第1張:Lottery
架構(gòu)
工程
第2張:API網(wǎng)關(guān)
架構(gòu)
工程
第3張:ChatGPT
那年我雙手插兜,略微出手?,就已經(jīng)能把你從青色的在校學(xué)習(xí)、編碼小白、CURD工具人,帶到一個(gè)P6工程師的水平!
不廢話,需要成長(zhǎng),就記得跟著小傅哥一起沖!掃碼加入,你會(huì)為你的選擇而感到幸福!因?yàn)槟阆热艘徊剑@得了更多的認(rèn)知。
此外,小傅哥還給大家準(zhǔn)備了一系列的《Java簡(jiǎn)明教程》視頻,進(jìn)入B站即可學(xué)習(xí)!
鏈接:https://www.bilibili.com/video/BV1fV4y1C7PW - 手把手教學(xué),非常適合小白。
B站:搜索 小傅哥の碼場(chǎng)