以下內容全是在專案中的體驗,個人理解心得

起源

2017年7月開始接觸.NetCore,當時還是因為Idr4的原因,之前的專案都是用的Idr3做,後面接觸到Idr4後,決定以後所有專案都使用.NetCore來搭建專案架構,隨後我開始研究Idr4的相關使用,後面又接觸到了Ocelot、Cap、Consul、Skywalking、AspectCore、MediatR等優秀庫,從此我決定搭建微服務專案,從此就走上了一條不歸路,接下來我闡述下我在在架構思想上的心得。

專案介紹

專案是一個學生體檢體檢專案,整體分為了認證中心、使用者服務、體檢服務三個部分

我建立了三個服務,這裡各自的專案人員開發自己的專案功能模組,分佈開發,多個專案組同時協作,使用者服務,體檢服務分別建立2個數據庫,當然這裡業務會存在服務呼叫服務的情況,前面的文章我也有說過,如果只是查詢,其實在UI端訪問2個不同服務介面就行了,但是如果存在內部業務需要呼叫另外一個服務的情況,這裡保證資料庫最終資料一致就行了,採用了訊息佇列RabbitMQ來處理,介面呼叫介面會出現的網路原因我也結合了Polly重試來處理,並記錄操作日誌,操作日誌採用面向切面是來實現(AOP),結合Exceptionless儲存日誌資訊,記錄引數詳細資訊

接下來就看是搭建專案結構基礎了,大體上我想的是下面這個結構,把所有的配置單獨出來,Domain層新增領域實體,這裡參見了eshopscontainer

領域層

大體結構已經建立好了後,根據業務新增好領域模型,確定了領取模型中領域職責事件,這是我對DDD的個人理解,這裡涉及到 聚合根(AggregateRoot)、值物件(ValueObject)等一些東西,為什麼要要說聚合根以及值物件,這可能涉及到一個認知改變,就是把EFCore模型中建立的關係型思想轉化為領域物件的認知思維,在以前的專案中記得經常有一個Model層一樣的東東,經常被用來承載資料,穿梭在各個結構層之間,這裡要說的Model在思想上可以認為是一個領域或者子領域,我個人是這麼理解 領域物件模型:定義或描述一個領域物件自身屬性、附屬關係(邊界)及領域行為的物件。

聚合根其實個人覺得跟EF中的上下文物件DbContext類似,打個比方:在DbContext中有很多 DbSet<T> 的物件,其實也可認為這個就是 DbContext下的邊界,而DbContext本生看作一個聚合根,所有的訪問都是DbContext下的 DbSet<T>實現對不同實體操作,定義這個邊界就是為了不讓從外部訪問它,需要通過在聚合根中的定義的邊界訪問,在實際的使用的過程中根據業務定義,這裡我在程式碼中為了不讓這個關係呈現在我的資料中,所以基本上我的每個領域模型我都是聚合根,這樣是我不想 因為聚合根中的邊界的依賴關係產生生成資料庫關聯關係成強主外來鍵關係,所以在這個專案中我 聚合根及值物件基本就被忽略了,從而我更加關注領域模型本生及領域模型中行為。

基礎層

基礎層我封裝了Exceptionless日誌處理,使用EFCore生產資料庫的Mapper配置及業務實現處理,以及上下問物件處理,這裡需要說的領域中的界限上下文,這裡我一個領域所以我只有一個上下文,這個根據業務劃分存在多個領域上下文物件,沒有劃分核心領域,子領域,一般一個領域(或子領域)對應有一個界限上下文,在服務上我已經分開了使用者服務於體檢服務,實際每個服務都是一個子領域,在結構上已經區分開了。在基礎層做了對IRepositry的倉儲以及MediatR的擴充套件從而實現消費領域事件。

應用層

應用層相對比較容易了,採用MediatR實現了命令式處理,在這中間我使用AOP封裝了操作日誌記錄操作資訊,查詢使用了Dapper實現了讀寫分離查詢,在MySql上做了一個主從,這裡特別害怕資料同步延遲,所以這裡的查詢我只用了那些只單單是查詢的方法,如果跟業務相關的查詢還是使用了EFCore,比如要根據查詢某一條結果然後某一條資料,使用MediatR 中的 INotification 去消費領域事件,另外我還在引用層添加了AggregateServices聚合服務相關處理,關於檔案儲存這塊使用了AliyunOSS,目前關於快取使用Redis做簡單的許可權資訊快取。

WebAPI

採用Autofac處理了接管了.NetCore的 DI,封裝了相關注入方式簡化了程式碼,另外對驗證做了擴充套件操作,採用Swagger構建API介面說明文件,處理了WebAPI的版本資訊

分散式目標

做了上面的架構後以實現下面的部署結構

以上是這段時間使用的技術構建的一套框架結構,以及在實際使用過程中的心得,以及思想上的認知