實戰分享|雲信IM SDK介面設計實踐
引語
IM (Instant Messaging)是網路上最流行的通訊方式,與日常生活息息相關。IM軟體也層出不窮,例如:微信、QQ、易信等。通過多年深耕和技術沉澱,雲信產出了一套成熟穩定的IM SDK架構。它提供了IM的主要功能,大大降低了第三方實現IM功能的難度。本文主要對IM介面設計實踐展開論述。
1 對外介面的設計準則
SDK對外提供介面設計的基本原則是易用,易懂,易擴充套件,易監控。展開來可歸納為以下幾個特性: 1. API按照業務功能分類,但所有業務具有統一的呼叫風格。 2. API不包含方法實現,介面的實現對呼叫者隱藏。 3. API呼叫可跟蹤。
在功能形式上,SDK需要提供以下型別的API: 1. 功能介面:主動呼叫使用其提供的功能 1.1. 同步介面:在呼叫執行緒完成函式呼叫,並立即返回結果。 1.2. 普通非同步介面:在後臺執行緒完成函式呼叫,可以新增回撥函式。 1.3. 可中斷非同步介面:在後臺執行緒完成函式呼叫,可以新增回撥函式,可以中斷呼叫。
2.回撥介面:監聽資料和狀態改變。
2 業務的分類
SDK包含多種業務,一部分是基礎業務,另一部分是可選業務。比如使用者認證服務、群服務等是基礎業務;超大群服務、第三方推送服務等是可選業務。另外,不同的業務之間難免有相似的功能,如群服務和超大群服務中,都有新增群成員,拉取群訊息等功能。因此,需要將不同的業務進行隔離,一方面方便業務功能的擴充套件與調整,另一方面方便函式的命名與使用者的理解。
同一個業務下有多個API,按照呼叫的主動性,分為回撥介面和功能介面,分別放在與業務一一對應的介面類Observer和Service中。例如:使用者認證服務下的所有回撥介面和功能介面都位於AuthServiceObserver和AuthService中。其中由使用者主動呼叫來實現功能的功能介面在AuthService中,如登入、登出等;而用於註冊回撥的回撥介面都在AuthServiceObserver中,如監聽線上狀態、監聽資料同步等。
每個Service中的功能介面根據執行的性質又分為三種,同步介面、普通非同步介面和可中斷非同步介面。其中同步介面在呼叫執行緒立即執行;非同步介面在後臺執行緒執行,在呼叫執行緒返回可設定回撥的InvocationFuture型別,最終結果在主執行緒回撥;可中斷非同步介面和普通非同步介面相似,但是返回的是繼承自InvocationFuture的AbortableFuture型別,支援中斷操作,使用者可以通過主動呼叫來中斷功能介面的執行。介面呼叫的執行緒切換流程如圖2.1所示,業務功能和介面的分類如圖2.2所示。
圖 2.1 介面呼叫的執行緒切換流程
圖 2.2 業務功能和介面的分類
3 API的實現
3.1 API的實現方式
為了實現這些目標,並考慮到實現簡單,我們選用Java的動態代理類模型。外部呼叫者呼叫API時,得到一個動態代理(Proxy)物件,通過Proxy物件,將功能介面的呼叫全部轉接到一個實現了InvocationHandler 介面的類ProxyHandler上。再根據呼叫方法,執行註冊/登出回撥或者將呼叫請求分派到真正的實現類上,最後根據介面的返回型別進行返回或回撥,如圖3.1所示。 圖 3.1 功能呼叫流程
和使用者服務的介面類AuthService和AuthServiceObserver一樣,SDK也為其他的所有業務定義了介面類。所有介面類和實現類呈一一對應關係,可以方便地找到API對應的實現。
3.2 獲取Proxy物件的方法
SDK對外提供了靜態方法NimClient.getService(Class clazz)來獲取業務介面類對應的動態代理類。引數填入對應的介面類即可。例如:獲取使用者認證服務的介面類的方式為NimClient.getService(AuthService.class),獲取使用者認證服務觀察者的介面類的方式為NimClient.getService(AuthServiceObserver.class)。
NimClient.getService方法同步返回一個Proxy物件。該物件的構造方式為懶載入,業務被呼叫的時候才構造對應例項。如圖3.2所示。
圖 3.2 獲取業務Proxy物件流程
生成Proxy物件基於Proxy.newProxyInstance方法,所有生成的Proxy物件都由專門的容器類來管理。以使用者認證服務為例,第一次呼叫NimClient.getService(AuthService.class)獲取使用者認證服務的Proxy物件時,容器理類建立一個對應的Proxy物件並快取。之後再次獲取使用者認證服務Proxy物件時,容器類將快取直接返回。
3.3 事務跟蹤類
invoke函式中有一個重要的事務跟蹤類(Transaction),它記錄了方法的同步非同步屬性、方法體和返回值要求等。Transaction物件和他的實現方法是一一對應的。每次執行invoke方法,都會建立一個Transaction例項,並傳輸到真正的執行點去執行
執行完畢後,invoke方法根據同步非同步特性以及返回值,來確定功能函式的返回結果。如果是同步函式,則直接返回結果;如果是非同步函式,則根據業務需求返回InvocationFuture或者AbortableFuture。
3.4 API的執行方式
NimClient.getService返回的是動態代理類ProxyHandler ,它實現了InvocationHandler介面的 Object invoke(Object who, Method method, Object[] args)方法,用於代理所有功能介面。
API執行方式,即ProxyHandler對invoke方法的實現方式,其大體步驟是載入事務、初始化判斷、執行事務和返回,如圖3.3所示。
圖 3.3 代理執行的簡要流程
執行事務這一環節還可以細分為回撥介面的執行和功能介面的執行,如果是執行回撥介面,則判斷是否需要回撥當前狀態,如果是,則立即回撥。
Transaction的執行函式是TransactionExecutor. execute方法,送出Transaction後,invoke方法會根據同步非同步屬性,決定是在當前執行緒執行,還是在後臺執行緒執行。用於非同步執行Transaction的後臺執行緒是唯一的,如果有多個Transaction需要被非同步執行,則會阻塞。
介面類的每個方法都被存進一個Map中,SDK以方法簽名實現了同名函式過載。執行Transaction時,通過方法所在的介面類找到對應的實現類,再呼叫對應的invoke方法即可。對於非同步方法,invoke方法的返回值不會被返回到上層,因此非同步API函式的實現不用關心返回值。代理的詳細執行流程如圖3.4所示
圖 3.4 代理的詳細流程
3.5 非同步方法的回撥
對於非同步方法,在TransactionExecutor. execute執行前,先基於Transaction生成對應的AbortableFuture的實現類TransactionFuture,然後將其快取,用於稍後的回撥。非同步方法執行完畢後,將子類返回到呼叫層。
在呼叫可中斷非同步介面後,同步返回的是AbortableFuture例項。呼叫方可以直接呼叫abort方法中止執行。例如:呼叫了用於下載訊息附件的downloadAttachment函式後,由於檔案太大,網路狀況不好等情況需要取消下載時,可以主動呼叫abort方法來終止。呼叫方式如圖3.5所示。可中斷非同步介面對應的abort方法由SDK內部實現,呼叫者不需要關心其實現方式。
圖 3.5 abort函式呼叫示例
TransactionFuture回撥的基本型別為RequestCallback,SDK在此基本型別中定義了onSuccess、onFailed和onException函式,分別用於在成功、失敗和異常情況下根據執行結果的不同,回撥到不同的函式。到此整個流程結束。
總結
雲信IM中,使用者可以通過NimClient.getService方法選擇業務的動態代理,然後根據業務需求在呼叫執行緒或者後臺執行緒執行功能,最後直接返回或者回撥結果。如果呼叫的是可中斷非同步介面,使用者還可以中斷操作。基於動態代理的實現方式,隔離了其他業務下的對外介面,並解耦了介面和實現,配合程式碼混淆,更進一步的提升隔離效果。
相關文章
- 融雲 IM 在 Electron 平臺上的設計實踐
- 短視訊 SDK 架構設計實踐架構
- angular 版 IM 聊天室|仿微信 App 介面|angular 實戰開發AngularAPP
- 【實戰分享】又拍雲 OpenResty / Nginx 服務優化實踐RESTNginx優化
- 使用Swift快速整合環信IM iOS SDK並實現單聊SwiftiOS
- 宜信智慧監控平臺建設實踐|分享實錄
- C++ 靜態反射在網易雲信 SDK 中的實踐C++反射
- 雲上深度學習實踐分享——雲上MXNet實踐深度學習
- 無埋點統計SDK實踐
- Laravel 中設計模式的實戰分享Laravel設計模式
- 融雲 IM SDK 整合 — 重新整理會話介面和會話列表介面會話
- Netty實戰:設計一個IM框架就這麼簡單!Netty框架
- 面向介面程式設計實踐之aspnetcoreapi的抽象程式設計NetCoreAPI抽象
- [譯] UX 設計實踐:如何設計可掃描的 Web 介面UXWeb
- 宜信微服務任務排程平臺建設實踐|分享實錄微服務
- 基於容器的金融資料庫雲平臺DBaaS設計實踐分享資料庫
- Java介面程式設計實戰(一)——簡易QQ登入介面Java程式設計
- 好程式設計師web前端分享js實現實戰案例程式設計師Web前端JS
- 介面自動化測試工程實踐分享
- 限流 SDK 的設計與實現
- 重學 Java 設計模式:實戰介面卡模式Java設計模式
- 整合環信IM SDK及使用注意事項
- 阿里雲 Serverless Kubernetes 的落地實踐分享阿里Server
- iOS VIPER架構實踐(三):面向介面的路由設計iOS架構路由
- Serverless 實戰 —— 函式計算 + Typescript 實踐Server函式TypeScript
- IM開發乾貨分享:萬字長文,詳解IM“訊息“列表卡頓優化實踐優化
- 微信域名防封API介面實現原理分享API
- Cocos Creator - 微信小遊戲 實戰分享遊戲
- 網易雲信 RTC 音訊問題排查的挑戰與實踐音訊
- Python專案實戰(一)《Python程式設計 從入門到實踐》Python程式設計
- Vue專案全域性配置微信分享實踐Vue
- Go程式設計實踐Go程式設計
- 作業幫多雲架構設計與實踐架構
- 阿里IM技術分享(五):閒魚億級IM訊息系統的及時性優化實踐阿里優化
- 阿里IM技術分享(四):閒魚億級IM訊息系統的可靠投遞優化實踐阿里優化
- 介面平臺實用功能設計分享——資料庫校驗資料庫
- 鴻蒙Next應用介面設計:國際化最佳實踐鴻蒙
- WKWebView實踐分享WebView