一、引言
在前面四篇文章中,咱們把物流中臺的基礎能力層構建了起來,接下來,咱們就能夠在這些基礎能力之上構建咱們的產品服務,從而支撐各條業務線。
基礎能力層主要關注的是穩定可用的原子接口,所以在設計的時候重點關注了不少高併發高可用的技術。產品服務層主要是爲了支撐不斷創新的業務,所以在設計的時候須要關注業務流程的可擴展性。下面咱們會先從總體上設計出一套抽象模型,而後針對模型的各個模塊深刻介紹。
一、總體設計
寫過業務代碼的同窗必定知道,咱們的系統每每是由service層、manager層和遠程服務層組成。這三層中,service層定義了對外的接口,manager層處理各類業務邏輯,主要是數據校驗、數據組裝、調用其餘應用的(dubbo服務,遠程服務層是對dubbo服務的包裝,比較簡單。當業務不斷膨脹的時候,咱們可能會遇到下面的狀況:
一、service層的接口愈來愈多,類似的業務定義多套接口
二、manager代碼愈來愈臃腫,各類if else嵌套,每次改一點都須要測試迴歸整塊業務
三、遠程服務,特別是查詢服務,在一條業務流程中的多個地方被重複調用,從而致使總體響應時間降低
對於第一個問題,咱們須要仔細分析業務,而後抽象出通用的接口,好比建立物流單,業務上既能夠建立快遞訂單,也能夠建立倉儲訂單,咱們須要定義一個通用的下單接口,而不是針對快遞和倉儲分別設計兩套訂單接口。而後,咱們在入參和出參上進行可擴展的設計,好比使用繼承、組合的方式,在保證入參模型基本不變的狀況下能夠支撐不一樣的業務,這樣一來,新業務接入的時候,就不須要更改接口,只須要擴展入參對象就行。
對於第二個問題,咱們把manager的業務邏輯抽象爲三個步驟:校驗、數據轉換、執行。快遞有快遞的校驗、數據轉換、執行,倉儲有倉儲的校驗、數據轉換、執行,service調用manager的時經過策略模式路由。這樣一來,各個業務都是不一樣的代碼流程,不存在修改一點會影響全局,測試只須要關注被修改的流程,新增的業務線只須要添加一條業務流程而後配置一下路由就能夠了,也不會影響老業務。
針對第三個問題,咱們能夠規定把全部的數據查詢都放在manager的數據轉換步驟,而後經過流程上下文去傳遞數據,這樣就不會把查詢服務擴散到整個流程了。
總結下上面的三個問題的解決方案,咱們能夠抽象出下面的業務流程模型:
二、接口層設計
產品服務層的接口服務遵循request-response風格,每一個方法的入參都是一個request,出參都是response。request和response經過繼承和組合進行擴展。
2.一、經過繼承擴展
request每每能夠經過繼承進行不一樣業務的擴展。以物流發貨來講,發貨方式有快遞發貨和倉儲發貨之分,這兩種發貨方式的入參不太同樣,這時候咱們能夠把公共的參數抽出來,而後不一樣的參數下沉。咱們會定義一個LogisticsServiceDTO對象,快遞和倉儲分別繼承它,獲得ExpressLogisticsServiceDTO和WarehouseLogisticsServiceDTO,而後各自定義參數,最後咱們就能夠獲得以下圖所示的一個request對象:
之後若是還有其餘新的發貨方式出現,咱們只須要定義新的LogisticsServiceDTO就能夠了,接口的基本結構幾乎不須要改變。
2.二、經過組合擴展
response每每能夠經過組合來擴展不一樣的業務,好比用戶物流單詳情頁,須要展現物流單信息、用戶信息和地址信息,咱們能夠定義一個OrderDetailResponse,這個對象組合了LogisticsOrderDTO、UserDTO、AddressDTO等對象。經過組合進行擴展的方式比較常見,在此就不展開講了。
2.三、如何定義方法
根據咱們的經驗,定義方法每每須要結合業務的生命週期,拿物流接口LogisticsService來舉例,咱們能夠定義createLogistics、consignLogistics、logisticsCallback這三個方法。
a)、createLogistics
createLogistics是建立物流訂單方法,經過定義可擴展的request對象,能夠支持快遞、倉儲、配送等等物流訂單的建立
b)、consignLogistics
consignLogistics是發貨方法,經過定義可擴展的request對象,能夠支持快遞、倉儲、配送等等物流訂單的發貨
c)、logisticsCallback
logisticsCallback是物流回傳方法,經過定義可擴展的request對象,能夠支持倉接單、倉分揀、倉出庫、配送攬收、配送派送、配送簽收等等物流回傳過程
三個方法基本上涵蓋了絕大部分業務場景,若是出現新的業務場景,首先須要評估現有的方法是否支持業務流程,若是不支持,再新增方法,好比有些物流場景存在多段發貨(典型的就是農村淘寶),這時候一個consignLogistics確定是不夠的,這時候就須要擴展方法。在擴展方法的時候,一開始能夠就爲特殊的業務開特殊的接口,等後面業務愈來愈多後,將這些特殊接口統一整理一次整理成一個通用的接口,這個過程就是一個沉澱業務模式的過程,是沒法經過提早設計設計出來的,必須通過業務的不斷沉澱才能跑出來。
三、接口實現層設計
說完了接口層的設計,接下來就要說說接口的實現層怎麼設計。按照總體設計的思路,咱們把業務切分紅一條一條的流程,而後把每條流程切分紅校驗、數據轉換、執行三個節點,而後經過入參來決策走哪條流程。所以,一個接口的實現層其實就是一個流程決策+流程節點執行的過程。
流程決策其實就是在一張映射表裏得到須要執行的節點列表,這裏獲取的方法能夠是普通的哈希映射,也能夠經過複雜的規則引擎獲取。拿到節點列表(通常是節點類名)後,就能夠經過spring容器獲取節點對象。全部的流程節點,都會繼承同一個抽象節點對象,而後實現同一個方法:execute方法,所以,經過spring容器獲取節點對象後,就能夠經過反射執行節點。節點與節點之間每每須要傳遞數據,所以節點的execute方法須要傳入一個context對象,A節點在執行後將數據傳入context對象,B節點執行的時候經過這個context對象獲取A的數據,這就打通了節點之間的數據通道。
將上面的抽象模型帶入具體的業務,咱們能夠獲得下面的架構:
以建立物流單爲例,全部的業務代碼都按照業務分散在不一樣的流程節點裏,入口處經過策略路由選擇流程,同一個流程規定了三個節點,三個節點之間經過流程上下文傳遞數據,三個節點通力合做完成不一樣業務的物流單的建立過程。
若是從更宏觀的視角來看,產品服務層和基礎能力層組合起來就是下面的架構:
產品服務層對外提供service,每一個service都定義了高度聚合的業務方法,每一個業務方法經過策略路由和流程編排,把業務代碼進行隔離,業務流程中的每一個節點,調用基礎能力層的原子接口進行一系列業務操做。
四、總結
產品服務平臺總的思路其實就是一條很是古老的原則:對擴展開放、對修改關閉。咱們經過繼承和組合,讓接口的出入參變得可擴展,經過策略模式和流程節點的組合,讓新老業務代碼隔離,進而提高了擴展性。固然,凡有利必有弊,產品服務平臺在提高了可擴展性的同時,增長了必定的代碼編寫量,同時對分佈式事務沒有太好的辦法。
更多文章歡迎訪問 http://www.apexyun.com/spring
聯繫郵箱:public@space-explore.com架構
(未經贊成,請勿轉載)併發