三方系統多渠道多場景的思考及程式碼分享

2023-07-21 06:00:33

一 背景

我們的業務中,經常會遇到多渠道+多場景的的需求。多渠道我們可以理解為,多個服務商同時為我們某一個功能提供服務,多場景就是同一個服務商下面的多種服務,我們通過幾個例子來具體看下:

我們有個電商平臺,系統在付款時候彈出選項,讓使用者自主選擇支付寶/微信/京東白條等支付,那麼這裡的支付寶、微信、京東我們都可以理解為他是我們的渠道。
同時,既然接入了支付寶/微信等,我們的系統就不再會單單使用他們的一個支付功能,還會涉及到對賬、退款等等操作,那麼這些操作,我們稱之為場景。

類似的,有的公司需要將訂單進行推播,根據訂單型別,推播到淘寶、拼多多等。那麼淘寶和拼多多也屬於渠道,同樣的,有了下單,那麼還會有退單、訂單對賬等都屬於場景。通過這樣的案例分析下來,我們會發現,我們身邊有很多這樣的需求。如果針對這類需求,我們的程式碼缺少一些架構設計,那麼就會帶來很多問題,比如:

  • 程式碼複用度不夠,新增需要會產生大量重複的冗餘程式碼;
  • 程式碼耦合度過高,業務邏輯和三方互動程式碼夾雜在一起,每次改動牽一髮而動全身,影響面不好評估。

此類問題應該存在一些通用的解決方案,可以實現以下特點:

  • 面向介面程式設計:業務方呼叫三方服務的時候,不需要關心具體服務商的實現,只針對介面呼叫;
  • 對拓展開放,對修改關閉:每次新增一個渠道,或者新增一個場景,對已有的程式碼應該是無衝突的,不需要改動的。

二 案例分析

2.1 下單支付案例

我們以下單支付為案例,通過時序圖的流程來梳理下我們的思路:

關於和三方請求的操作,一般就分為兩類:

  • 請求三方系統;
  • 三方系統處理完成,回撥通知。

2.2 請求類

請求三方系統的具體流程如下:

不同場景下,流程相同,但是還會存在一些差異點,我們總結一下:

  • 通用:資料加簽/加密,重試+告警,返回結果解密,操作紀錄檔記錄等;
  • 差異:模型轉換欄位不一樣,發起請求的方式和路徑不一樣;

2.3 回撥類


不同回撥場景也可能會存在一些差異,我們總結一下:

  • 通用:回撥紀錄檔記錄,資料解密,響應三方系統;
  • 差異:模型轉換欄位不一樣,執行業務操作不一樣;

2.4 渠道商的拓展

多渠道多業務通過以上分析基本上都是可以列舉的,可以通過以下表格進行拓展:

三 程式碼實現

程式碼已開源到Github:https://github.com/Shiyajian/mall-example
程式碼可能執行有問題,主要展示的是思路,下面是針對專案的講解。

3.1 設計思路

通過案例分析,我們分析出來了通用和差異點,對於通用的部分,我們採用封裝成標準流程,差異的地方,我們定義拓展點介面,不同渠道方各自實現,每個渠道方的程式碼要物理隔離。

3.2 程式碼結構分包

程式碼主要分為三部分:核心業務程式碼、架構程式碼、拓展實現程式碼。

  • 核心業務程式碼:就是我們平常寫的業務程式碼,應該和具體的三方系統互動解耦,面向介面程式設計,不感知三方系統模型,也不感知具體的渠道實現。
  • 架構程式碼:根據不同的渠道和場景,找到對應的實現,並且提供部分流程編排能力
  • 拓展點介面定義:抽象的能力介面和公用;
  • 拓展點實現程式碼:不同場景不同渠道的實現。

3.3 spi 介面定義


主要使用策略模式,這裡通過介面進行抽象定義,程式碼主要分為三個部分:

  • call :表示呼叫第三方渠道商的抽象服務介面;
  • callback:表示第三方渠道商回撥業務系統的介面,每個場景按包進行細分
  • common:一些公用的列舉和標記性介面定義

拓展方式:

  • 如果需要新增呼叫渠道商的介面,那麼在 ChannelCaller中定義方法,在 spi-impl 中實現;
  • 如果需要新增回撥方法,首先在 ChannelCallbackSceneEnum 中增加型別,在 callback 中新增一個包,新建一個 request 模型和 parser 模型,request 表示渠道方傳入的引數,parser 表示如何轉換成我們業務系統模型;

3.4 spi 實現方式


每個渠道商為一個package,裡面實現 call 和 callback 定義的介面即可,按需自己增加常數和工具類等;

3.5 spi的發現及路由


通過 Manger 管理類進行查詢具體實現,並進行一定業務邏輯的編排,處理紀錄檔記錄,錯誤處理等通用流程。

3.6 業務程式碼使用

需要呼叫渠道商介面的時候,通過以下方式進行呼叫:

@Override
public String pay(ChannelCodeEnum channelCode, Object args) {
    // 1、建立支付單;
    PayOrder payOrder = new PayOrder();
    // 2、支付單入庫;

    // 3、根據不同支付渠道,呼叫三方的支付單建立
    ChannelCaller channelCaller = channelCallerManager.of(channelCode);
    channelCaller.submitPay(payOrder);

    // 4、更新三方訂單號入庫

    // 5、返回前端喚醒引數
    return payOrder.getPayParams();
}

渠道商介面回撥時候,通過下面方式進行引數的轉換,轉換完成後執行自己系統邏輯:

@RequestMapping("/pay/{channelCode}/{bizNo}")
public ResponseEntity<?> paySuccessCallback(HttpServletRequest request,
                    @PathVariable(value = "channelCode") String channelCode,
                    @PathVariable(value = "bizNo") String bizNo) {

    log.info("進入[" + channelCode + "]支付成功回撥:bizNo:[" + bizNo + "] ");

    ChannelCodeEnum channelCodeEnum = ChannelCodeEnum.ofCode(channelCode);
    return channelCallbackHandlerManager.run(channelCodeEnum, () -> {
        CallbackPayRequest payRequest = channelRequestParserManager.parse(channelCodeEnum, ChannelCallbackSceneEnum.PAY_CALLBACK, request, bizNo);
        return payService.paySuccess(payRequest);
    });
}

結束語

上面就是我在專案開發中,針對多渠道+多場景的一些思考及個人的程式碼設計。由於經驗有限,此方案不一定是最優方案,歡迎大家批評指正,感謝。

求職

上份工作由於公司的資金鍊問題,失業了,現在找份工作,我簡單介紹下自己。
優勢:

  • 8年工作經驗,有架構、中臺、微服務等經驗,有虛線管理(10人以下經驗),有中廠工作經驗;
  • 檔案能力較強、程式碼質量和整潔度較高,有一定程式碼潔癖;
  • 抗壓能力強、溝通能力強、技術熱情高、喜歡分享;

劣勢:

  • 簡歷比較花,最近2年3次被裁,都是因為公司業務問題非個人問題;
  • 文科專業,跨行入門。
    如果你們公司是個小而美的公司,而且缺人,感覺我還不錯,歡迎 call 我,我個人還是屬於價效比比較高的。
    微信: 153 5500 0708 (如果不是推薦工作,單純交友也可以加)
    不考慮中大廠(阿里、位元組、得物等大中廠),只考慮小廠,創業公司也可以……,不是瞧不上大廠,現在環境下,大廠要求太高,我的簡歷篩選基本不會過,所以不去嘗試了,曾經位元組也在HR面被刷了,所以已經對大廠不抱希望了。