1. 程式人生 > >[Thrift]Apache Thrift入門Java例項

[Thrift]Apache Thrift入門Java例項

1. 概述

Apache Thrift 是 Facebook 實現的一種高效的、支援多種程式語言的遠端服務呼叫的框架。本文將從 Java 開發人員角度詳細介紹 Apache Thrift 的架構、開發和部署,並且針對不同的傳輸協議和服務型別給出相應的 Java 例項,同時詳細介紹 Thrift 非同步客戶端的實現,最後提出使用 Thrift 需要注意的事項。

目前流行的服務呼叫方式有很多種,例如基於 SOAP 訊息格式的 Web Service,基於 JSON 訊息格式的 RESTful 服務等。其中所用到的資料傳輸方式包括 XML,JSON 等,然而 XML 相對體積太大,傳輸效率低,JSON 體積較小,新穎,但還不夠完善

。本文將介紹由 Facebook 開發的遠端服務呼叫框架 Apache Thrift,它採用介面描述語言定義並建立服務,支援可擴充套件的跨語言服務開發,所包含的程式碼生成引擎可以在多種語言中,如 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk 等建立高效的、無縫的服務,其傳輸資料採用二進位制格式,相對 XML 和 JSON 體積更小,對於高併發、大資料量和多語言的環境更有優勢。本文將詳細介紹 Thrift 的使用,並且提供豐富的例項程式碼加以解釋說明,幫助使用者快速構建服務。

2. Maven依賴

在這裡,我使用的是0.9.3版本:

  1. <!-- https://mvnrepository.com/artifact/org.apache.thrift/libthrift -->
  2. <dependency>
  3. <groupId>org.apache.thrift</groupId>
  4. <artifactId>libthrift</artifactId>
  5. <version>0.9.3</version>
  6. </dependency>

3. 安裝 Thrift compiler

在編譯.thrift檔案時需要用到

  1. [email protected]
    :/opt/apache-flume-1.6.0-bin$ sudo apt-get install thrift-compiler
  2. [sudo] xiaosi 的密碼:
  3. 正在讀取軟體包列表...完成
  4. 正在分析軟體包的依賴關係樹
  5. 正在讀取狀態資訊...完成
  6. 下列【新】軟體包將被安裝:
  7.  thrift-compiler
  8. 升級了0個軟體包,新安裝了1個軟體包,要解除安裝0個軟體包,有162個軟體包未被升級。
  9. 需要下載819 kB 的軟體包。
  10. 解壓縮後會消耗掉2,944 kB 的額外空間。
  11. 獲取:1 http://cn.archive.ubuntu.com/ubuntu/ wily/universe thrift-compiler amd64 0.9.1-2 [819 kB]
  12. 下載819 kB,耗時0(982 kB/s)
  13. 正在選中未選擇的軟體包 thrift-compiler
  14. (正在讀取資料庫...系統當前共安裝有273041個檔案和目錄。)
  15. 正準備解包.../thrift-compiler_0.9.1-2_amd64.deb  ...
  16. 正在解包 thrift-compiler (0.9.1-2)...
  17. 正在處理用於 man-db (2.7.4-1)的觸發器...
  18. 正在設定 thrift-compiler (0.9.1-2)...

4. 建立Thrift檔案

在安裝Thrift編譯器之後,我們需要建立一個.thrift檔案,在這裡我們在main資料夾下建立calculator.thrift檔案。

這個檔案是一個介面定義(服務)檔案。這些服務會被伺服器端實現,被客戶端呼叫。伺服器端和客戶端下面會講解到。

  1. // defines the namespace
  2. namespace java com.sjf.open
  3. service CalculatorService{
  4.    i32 add(1:i32 num1,2:i32 num2)
  5.    i32 minus(1:i32 num1,2:i32 num2)
  6.    i32 multi(1:i32 num1,2:i32 num2)
  7.    i32 divi(1:i32 num1,2:i32 num2)
  8. }

其中定義了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檔案:

  1. thrift --gen <language><Thrift filename>

在我們例子中,命令為:

  1. [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類是介面的實現類。

  1. package com.sjf.open;
  2. import org.apache.thrift.TException;
  3. /**
  4. * Created by xiaosi on 16-9-20.
  5. */
  6. publicclassCalculatorHandlerimplementsCalculatorService.Iface{
  7. publicint add(int num1,int num2)throwsTException{
  8. return num1 + num2;
  9. }
  10. publicint minus(int num1,int num2)throwsTException{
  11. return num1 - num2;
  12. }
  13. publicint multi(int num1,int num2)throwsTException{
  14. return num1 * num2;
  15. }
  16. publicint divi(int num1,int num2)throwsTException{
  17. if(num2 ==0){
  18. thrownewRuntimeException("分母不能為0");
  19. }
  20. return num1 / num2;
  21. }
  22. }

7. 建立伺服器端CalculatorServer

建立伺服器端實現程式碼,將 CalculatorHandler 作為具體的處理器傳遞給 Thrift 伺服器。

  1. package com.sjf.open;
  2. import org.apache.thrift.server.TServer;
  3. import org.apache.thrift.server.TSimpleServer;
  4. import org.apache.thrift.transport.TServerSocket;
  5. import org.apache.thrift.transport.TServerTransport;
  6. /**
  7. * Created by xiaosi on 16-9-20.
  8. */
  9. publicclassCalculatorServer{
  10. privatestaticint port =9090;
  11. privatestaticCalculatorHandler handler;
  12. privatestaticCalculatorService.Processor processor;
  13. /**
  14.     * 啟動伺服器
  15.     * @param processor
  16.     */
  17. publicstaticvoid start(CalculatorService.Processor processor){
  18. try{
  19. TServerTransport serverTransport =newTServerSocket(port);
  20. TServer server =newTSimpleServer(newTServer.Args(serverTransport).processor(processor));
  21. // Use this for a multithreaded server
  22. // TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));
  23. System.out.println("Starting the simple server...");
  24.            server.serve();
  25. }catch(Exception e){
  26.            e.printStackTrace();
  27. }
  28. }
  29. publicstaticvoid main(String[] args){
  30.        handler =newCalculatorHandler();
  31.        processor =newCalculatorService.Processor(handler);
  32.        start(processor);
  33. }
  34. }

8. 建立客戶端CalculatorClient

建立客戶端實現程式碼,呼叫 CalculatorService.client 訪問服務端的邏輯實現。

  1. package com.sjf.open;
  2. import com.google.common.base.Objects;
  3. import org.apache.thrift.TException;
  4. import org.apache.thrift.protocol.TBinaryProtocol;
  5. import org.apache.thrift.protocol.TProtocol;
  6. import org.apache.thrift.transport.TSocket;
  7. import org.apache.thrift.transport.TTransport;
  8. import org.apache.thrift.transport.TTransportException;
  9. /**
  10. * Created by xiaosi on 16-9