網易實戰分享|雲信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所示。spa

圖 3.1 功能調用流程

和用戶服務的接口類AuthService和AuthServiceObserver同樣,SDK也爲其餘的全部業務定義了接口類。全部接口類和實現類呈一一對應關係,能夠方便地找到API對應的實現。線程

3.2 獲取Proxy對象的方法

SDK對外提供了靜態方法NimClient.getService(Class<T> 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對象時,容器類將緩存直接返回。3d

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函數,分別用於在成功、失敗和異常狀況下根據執行結果的不一樣,回調到不一樣的函數。到此整個流程結束。

4. 總結

雲信IM中,用戶能夠經過NimClient.getService方法選擇業務的動態代理,而後根據業務需求在調用線程或者後臺線程執行功能,最後直接返回或者回調結果。若是調用的是可中斷異步接口,用戶還能夠中斷操做。基於動態代理的實現方式,隔離了其餘業務下的對外接口,並解耦了接口和實現,配合代碼混淆,更進一步的提高隔離效果。
相關文章
相關標籤/搜索