国产欧美另类视频第一页-国产视v频一区二区三区不卡视频-国产精品亚洲v无码播放-亚洲欧美三级另类

業務中臺構建-服務識別

SOA團隊 2020-03-16

對于中臺構建,實際上兩個關鍵點,第一個是劃分微服務模塊粒度,第二個就是在模塊劃分清楚后確定服務識別和定義的粒度。在服務識別和定義前,可以先參考本文檔【3.2.2.2 Http Rest接口設計】這篇文章。

在上篇談中臺構建模塊劃分的時候,強調了一個關鍵點,就是盡可能以數據的維度來進行模塊拆分,數據包括了基礎主數據和核心共享數據,在數據驅動下拆分模塊,那么模塊底層對應的數據庫如何拆分基本也就清楚了。一定要知道,微服務架構下,我們底層數據庫也是拆分了的。

底層數據庫沒有拆分,但是仍然用SpringCloud框架開發,可以拆分為多個JAR包,在這種模式下只能認為是一個微服務模塊,而不是獨立,因為其不存在獨立自治能力。我們看到很多上層開發采用SpringCloud框架,但是數據庫仍然采用一個數據庫的情況,再次說明,對于這種架構設計,不是標準意義上的微服務架構,沒有做到徹底解耦。

面向資源,面向對象和領域驅動設計

對于Http Rest接口說的最多的就是面向資源的設計,對于資源有標準的Http Put,Post,Delte,Get等操作。因此你需要定義好相應的資源。資源可以放在計算機上并體現為比特流的事物,可以是結構化的數據或對象集合,也可以是圖片或文件流,這些都是可以處理和操作的資源。

面向資源和領域驅動本身不是一種新的軟件工程設計方法,真正的方法只有傳統的面向結構設計和面向對象設計兩種。因此對于面向資源可以按面向傳統結構化設計,也可以按面向對象設計。當然最好的方式仍然是面向對象進行設計。

資源即實體,實體即對象,這個對象代表的是業務對象,有明確的業務含義,類似供應商,采購訂單,產品,合同等。同時這些對象本身存在關聯和遞進的層次結構,比如供應商有對應的聯系人,有對應的銀行賬號。產品可能有對應的維修記錄等。

而這些業務對象正是我們在領域驅動設計時候經常會識別的領域對象,這個領域對象涉及到多個子類,是否歸結到一個大的領域對象最關鍵的還是是否共屬一個生命周期。面向資源設計,完全可以采用面向領域設計方法,首先定義領域對象,將領域對象建模為對應的資源,然后再考慮看這個資源應該暴露哪些能力接口出來。

所以在微服務架構下,首先要了解清楚面向資源進行Rest接口能力設計,資源的識別和定義可以參考領域設計的思路進行,識別和定義領域對象,然后再轉為資源定義。

接口服務的粗粒度是關鍵

如果我們不按領域對象方式來定義資源,那么我們最容易犯的錯誤就是將所有的數據庫表對象都全部定義為一個個獨立的資源,將這些資源的CRUD操作,全部暴露為Get,Put,Post和Delete接口方法。那么這樣暴露出來的Http Rest接口方法就全部是細粒度的接口。

這種方法很省事,一個模塊有100張表,你只需要暴露100個接口,每個接口都含標準的上述操作就完事了。但是這種接口服務識別和定義沒有任何意義,也不符合我們粗粒度的要求。

那么問題的關鍵點在哪里?其關鍵就是原來應該是粗粒度的體現業務價值的接口服務全部都變成了細粒度的DAO訪問類細粒度接口服務。失去了接口的意義,同時又將本身應該完全內聚在微服務模塊內部的業務邏輯全部暴露到外層去解決。這個有點類似我們在進行領域驅動設計的時候,經常談到的貧血的領域服務層,即我們的Http Rest接口應該是粗粒度的,應該是滿血的領域服務層的能力暴露,而不是底層數據庫CRUD操作的暴露。

通過識別的資源來識別和定義接口

只要確定了資源,那么我們就很容易來確定資源應該提供哪些接口。

在我們進行接口設計的時候,如果一個資源完全不需要和外部微服務模塊或外部應用打交道,那么這個資源完全不用開放任何接口。這個是我一直強調的原則,即在微服務模塊內部最好是走傳統API接口交付方法進行調用,而不是走Http Rest接口服務,這一方面是提升性能,一方面是減少各類難以應對的分布式事務問題。

在資源定義清楚后,往往資源都是一個復合對象,比如采購訂單資源,涉及到采購訂單頭或采購訂單明顯信息,之間還存在關聯,但是這是一個完整的資源對象。對于采購訂單對象,根據業務場景,存在外部導入新的采購訂單,存在外部對已有的采購訂單進行變更后導入,存在外部需要查詢采購訂單集合,同時查看某一個特定key值的采購訂單的詳細明細數據。這可能是我們經常會遇到的接口需求場景,從這些場景可以看到,我們的設計完全可以基于采購訂單資源展開。

創建新的采購訂單:POST /Orders

修改一張ID為1的已有訂單:PATCH /Orders/1

刪除ID為1的已有訂單:DELETE /Orders/1

查詢所有采購訂單:GET /Orders

查詢ID為1的采購訂單:GET /Orders/1

查詢1月到5月的訂單:GET /Orders?StartData='201801'&&EndDate='201805'

可以看到,第一種方法就是上面的,可以直接在資源后面增加不同的參數條件進行模糊查詢。其次,我們可以將查詢條件定義為一個查詢實體類,同時將整個查詢實體類的信息通過一個完整的實體對象傳遞過去進行查詢,查詢完成后再返回相應的結果。比如我們定義一個OrderQueryExt實體類。

基于特定條件的模糊查詢:POST /Orders/OrderQueryExt

那是否會存在只查詢一張采購訂單的采購明細列表信息?如果存在這種情況,應該按照資源和資源層次關系進行設計,由資源逐層展開查詢。

查詢ID為1的訂單的所有采購明細:GET /Orders/1/OrderDetails

查詢ID為1的訂單的流程審批記錄信息:GET /Orders/1/ProcessDetails

查詢ID為1的訂單的所有附件信息:GET /Orders/1/Attaches

對于PUT和PATCH而言,如果涉及的情況一般是對實體的部分數據進行更新,同時還需要支持SaveAndUpdate操作,那么我們一般都采用PATCH方式,而不是PUT方式。即實際資源接口設計的時候,單純的PUT場景往往現在已經很少發生。

定義業務規則和邏輯處理類接口

這是我們遇到的第二大類,前面基于資源進行接口設計思路已經很明確。但是對于業務規則處理類往往比較難,比如我們經常遇到的提交報賬單的時候需要進行預算校驗和控制,這個就是典型的業務規則處理類,報賬單提交需要,合同提交往往也需要。

那么這里的資源究竟是什么?

對于預算信息應該不是這里的資源,因為預算信息的錄入和維護,才會涉及到預算信息開放接口。而這里的業務場景是對已有的預算信息進行規則計算和校驗。

基于這類場景,我們看到比較好的設計方法是定義一個獨立的規則類,將規則類映射為一個資源,比如這例子里面我們可以定義一個BudgetControl的規則類,這個類可以定義為一個資源對象。任何一個規則處理都涉及到有具體的輸入和輸出。

比如預算校驗:

輸入:具體的組織信息,預算科目信息,當前申請預算信息,年度或月度信息

輸出:校驗結果信息

你會看到對于預算校驗,預算扣減,預算凍結,實際上他們的輸入和輸出都是相同的,那么我們可以劃歸到同一個規則處理類里面進行處理。那么規則類的定義,需要增加一個規則處理類型即可。

那么不論是預算校驗,還是預算凍結,可以看到實際的接口調用都是:

POST /BudgetControls

當然也可以將預算檢查,預算凍結等定義為預算控制類的子對象,比如預算檢查Valid,那接口調用為:

POST /BudgetControls/Valid

所以對于業務規則的處理可以看到,最重要的是業務規則類的定義,業務規則類定義清楚了,業務規則類轉為資源,形成對資源的Http操作接口。

對于業務規則類,一定是粗粒度服務接口,規則的處理邏輯都應該完全控制在模塊內部而不是被暴露到外面去。因此對于規則類的定義也是,僅僅提供僅有的輸入和輸出,能夠滿足規則處理和計算要求即可。

返回上頁