[Thrift]Apache Thrift入門Java例項
1. 概述
Apache Thrift 是 Facebook 實現的一種高效的、支援多種程式語言的遠端服務呼叫的框架。本文將從 Java 開發人員角度詳細介紹 Apache Thrift 的架構、開發和部署,並且針對不同的傳輸協議和服務型別給出相應的 Java 例項,同時詳細介紹 Thrift 非同步客戶端的實現,最後提出使用 Thrift 需要注意的事項。
目前流行的服務呼叫方式有很多種,例如基於 SOAP 訊息格式的 Web Service,基於 JSON 訊息格式的 RESTful 服務等。其中所用到的資料傳輸方式包括 XML,JSON 等,然而 XML 相對體積太大,傳輸效率低,JSON 體積較小,新穎,但還不夠完善
2. Maven依賴
在這裡,我使用的是0.9.3版本:
<!-- https://mvnrepository.com/artifact/org.apache.thrift/libthrift -->
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.9.3</version>
</dependency>
3. 安裝 Thrift compiler
在編譯.thrift檔案時需要用到
[email protected]
[sudo] xiaosi 的密碼:
正在讀取軟體包列表...完成
正在分析軟體包的依賴關係樹
正在讀取狀態資訊...完成
下列【新】軟體包將被安裝:
thrift-compiler
升級了0個軟體包,新安裝了1個軟體包,要解除安裝0個軟體包,有162個軟體包未被升級。
需要下載819 kB 的軟體包。
解壓縮後會消耗掉2,944 kB 的額外空間。
獲取:1 http://cn.archive.ubuntu.com/ubuntu/ wily/universe thrift-compiler amd64 0.9.1-2 [819 kB]
下載819 kB,耗時0秒(982 kB/s)
正在選中未選擇的軟體包 thrift-compiler。
(正在讀取資料庫...系統當前共安裝有273041個檔案和目錄。)
正準備解包.../thrift-compiler_0.9.1-2_amd64.deb ...
正在解包 thrift-compiler (0.9.1-2)...
正在處理用於 man-db (2.7.4-1)的觸發器...
正在設定 thrift-compiler (0.9.1-2)...
4. 建立Thrift檔案
在安裝Thrift編譯器之後,我們需要建立一個.thrift檔案,在這裡我們在main資料夾下建立calculator.thrift檔案。
這個檔案是一個介面定義(服務)檔案。這些服務會被伺服器端實現,被客戶端呼叫。伺服器端和客戶端下面會講解到。
// defines the namespace
namespace java com.sjf.open
service CalculatorService{
i32 add(1:i32 num1,2:i32 num2)
i32 minus(1:i32 num1,2:i32 num2)
i32 multi(1:i32 num1,2:i32 num2)
i32 divi(1:i32 num1,2:i32 num2)
}
其中定義了CalculatorService服務的4個方法,每個方法包含一個方法名,引數列表和返回型別。每個引數包括引數序號,引數型別以及引數名(1:i32 num1)。 Thrift 是對 IDL(Interface Definition Language) 描述性語言的一種具體實現。因此,以上的服務描述檔案使用 IDL 語法編寫。使用 Thrift 工具編譯 Calculator.thrift,就會生成相應的 CalculatorService.java 檔案。namespace 定義了名稱空間,在java中為包,在這裡我們會在com.sjf.open包下生成CalculatorService.java 檔案。
5. 編譯Thrift檔案
Thrift編譯器會將thrift檔案編譯成Java程式碼。使用下面的命令編譯.thrift檔案:
thrift --gen <language><Thrift filename>
在我們例子中,命令為:
[email protected]:~/code/open/openDiary/ThriftDemo/src/main$ thrift --gen java calculator.thrift
編譯之後,會在gen-java資料夾下建立com.sjf.open包,並在包下生成CalculatorService.java 檔案。
該檔案包含了在 Calculator.thrift 檔案中描述的服務 CalculatorService 的介面定義,即 CalculatorService.Iface 介面,以及服務呼叫的底層通訊細節,包括客戶端的呼叫邏輯 CalculatorService.Client 以及伺服器端的處理邏輯 CalculatorService.Processor,用於構建客戶端和伺服器端的功能。
6. 建立Service Handler類
Service handler 類必須實現 CalculatorService.Iface介面。Handler類是介面的實現類。
package com.sjf.open;
import org.apache.thrift.TException;
/**
* Created by xiaosi on 16-9-20.
*/
publicclassCalculatorHandlerimplementsCalculatorService.Iface{
publicint add(int num1,int num2)throwsTException{
return num1 + num2;
}
publicint minus(int num1,int num2)throwsTException{
return num1 - num2;
}
publicint multi(int num1,int num2)throwsTException{
return num1 * num2;
}
publicint divi(int num1,int num2)throwsTException{
if(num2 ==0){
thrownewRuntimeException("分母不能為0");
}
return num1 / num2;
}
}
7. 建立伺服器端CalculatorServer
建立伺服器端實現程式碼,將 CalculatorHandler 作為具體的處理器傳遞給 Thrift 伺服器。
package com.sjf.open;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
/**
* Created by xiaosi on 16-9-20.
*/
publicclassCalculatorServer{
privatestaticint port =9090;
privatestaticCalculatorHandler handler;
privatestaticCalculatorService.Processor processor;
/**
* 啟動伺服器
* @param processor
*/
publicstaticvoid start(CalculatorService.Processor processor){
try{
TServerTransport serverTransport =newTServerSocket(port);
TServer server =newTSimpleServer(newTServer.Args(serverTransport).processor(processor));
// Use this for a multithreaded server
// TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));
System.out.println("Starting the simple server...");
server.serve();
}catch(Exception e){
e.printStackTrace();
}
}
publicstaticvoid main(String[] args){
handler =newCalculatorHandler();
processor =newCalculatorService.Processor(handler);
start(processor);
}
}
8. 建立客戶端CalculatorClient
建立客戶端實現程式碼,呼叫 CalculatorService.client 訪問服務端的邏輯實現。
package com.sjf.open;
import com.google.common.base.Objects;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
/**
* Created by xiaosi on 16-9