Huli's Blog

Learning by sharing

Lidemy 鋰學院是一個為初學者而生的線上程式課程平台,希望能以淺顯易懂的教學,帶領初學者更快速地入門程式設計。你可以直接到網站註冊,或者是追蹤 Lidemy 的粉絲專頁,就能搶先得知課程的最新消息

[Android] apache thrift 入門與android上的實作

| Comments

最近想做IM相關的service,上網找了一些文件
發現一套由facebook開源,LINE有在用的RPC的framework,也就是今天要介紹的主角
Apache Thrift

先來談談有這套框架跟沒這套框架的差異在哪邊
假設今天我要寫一套IM,client跟server之間透過http以json格式溝通
例如說client發一個request到api/getFriends,server就回覆

{
    list: [
    ....
  ]
}

這樣做會碰到幾個問題

  1. 透過http傳輸,你根本不需要header裡面的資訊,但又不可能捨棄
  2. 如果哪天server要用別的語言改寫,怎麼辦? 如果有寫好document,就是直接照著之前的document重新實做一份 沒有的話就只能看著以前的code,一步步改寫成新的語言

這個時候就來介紹Thrift可以怎麼解決這些問題了
基本上這就是一套RPC的framework

你必須用thrift規範的格式寫好一份檔案,我直接把它看成api的document,例如說

service Calculator extends shared.SharedService {

  void ping(),
  i32 add(1:i32 num1, 2:i32 num2)
}

就說你有一個Calculator的service,有兩個function,pingadd
i32其實就是32 bits的int

有了這份以後,可以用thrift把它compile成串接API所需要的檔案
thrift --gen <language> <Thrift filename>
thrift的強大之處就在這裡,你要用java來實作server,就編譯成java的檔案
你要用python寫client,你就編譯出.py的檔案

先以java做server為例,compile完以後就會有一份.class檔案
import進去以後就可以implements Calculator.Iface,實作你剛剛定義的那兩個function

client端的操作也很簡單,也是把剛剛編譯出來的檔案import進去
跟server建立連線以後就可以直接呼叫了

再來就研究一下怎麼在android上面實作出client
一開始我是在gradle上面直接直接 compile 'org.apache.thrift:libthrift:0.9.1'
後來發現這樣子會出現錯誤,因為裡面用到的http連接的class跟android本身的會衝突
所以不能直接這樣引入thrift
解法附在最底下的ref裡面,你要自己改code然後編譯出一個thrift的jar檔放入

但網路資源豐富,android-thrift-tutorial這個repo底下就有這個jar檔,所以我就直接下載下來之後compile files('libs/libthrift-0.9.1.jar')

除此之外我們還需要兩個thrift會用到的library

compile 'org.slf4j:slf4j-api:1.5.8'
compile 'org.slf4j:slf4j-log4j12:1.5.8'

補充說明:
android會一直說找不到javax.annotation
可參考 Thrift: the import javax.annotation cannot be resolved
加入一個jar檔之後即可

加入這三行以後試著執行一下,應該就可以成功開啟了

在這邊我所定義的thrift檔是一個getMessage的function

service Message {
    string getMessage(1:string username)
}

android端因為是牽扯到網路連線,所以必須放在asynctask裡面

private class ThriftTask extends AsyncTask<String, Integer, String> {

    @Override
    protected String doInBackground(String... str) {
        try {
            TTransport transport;

            transport = new TSocket("127.0.0.1", 9090);
            transport.open();

            TProtocol protocol = new TBinaryProtocol(transport);
            Message.Client client = new Message.Client(protocol);

            String ret = client.getMessage("huli");
            transport.close();

            return ret;
        } catch (TException x) {
            x.printStackTrace();
        }

        return "";
    }

    protected void onProgressUpdate(Integer... progress) {

    }

    protected void onPostExecute(String result) {
        Log.d("APP", "thrift");
        Log.d("APP", result);
    }
}

Message.ClientMessage就是thrift所產生的.java檔案
儘管我只定義了一個function,但產生的code足足有兩千多行
可見thrift背後幫你把一大堆事情都處理掉了

接著呼叫new ThriftTask().execute();
就可以在logcat看到api所傳來的結果

以我初步試驗的結果,覺得thrift還不錯,假設哪天要換server或是在別的client(web、desktop)也能迅速切換
不用再從頭開始打造

google有一套protobuf也跟這個類似,只是支援的語言好像比較少

thrift的中文討論非常少,如果之後有進一步使用或碰到什麼問題,再上來跟大家分享

Evenote也在用這套 So API Together: Evernote and Thrift
裡面提到facebook後來自己又open source改進的版本 Under the Hood: Building and open-sourcing fbthrift

evenote有把自己thrift格式開源出來,要規劃API可以參考看看
evernote-thrift
line的則是有人破解出來XDD
purple-line

ref:
关于解决 java.lang.NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder 的解决方法
Apache Thrift » 0.9.2
Thrift 0.8 not compatible with Android HttpClient
Thrift client on Android
android-thrift-tutorial
Thrift by Example
Apache-Thrift-Bootcamp

Comments

comments powered by Disqus