Thrift入門及Java實例演示

來源:http://www.micmiu.com/soa/rpc/thrift-sample/

Thrift入門及Java實例演示

目錄:

  • 概述
  • 下載配置
  • 基本概念
    1. 數據類型
    2. 服務端編碼基本步驟
    3. 客戶端編碼基本步驟
    4. 數據傳輸協議
  • 實例演示(java)
    1.  thrift生成代碼
    2.  實現接口Iface
    3. TSimpleServer服務模型
    4. TThreadPoolServer 服務模型
    5. TNonblockingServer 服務模型
    6. THsHaServer服務模型
    7. 異步客戶端

[一]、概述

Thrift是一個軟件框架,用來進行可擴展且跨語言的服務的開發。它結合了功能強大的軟件堆棧和代碼生成引擎,以構建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 等等編程語言間無縫結合的、高效的服務。

Thrift最初由facebook開發,07年四月開放源碼,08年5月進入apache孵化器。thrift允許你定義一個簡單的定義文件中的數據類型和服務接口。以作爲輸入文件,編譯器生成代碼用來方便地生成RPC客戶端和服務器通信的無縫跨編程語言。

官網地址:thrift.apache.org

推薦值得一看的文章:

[二]、下載配置

到官網下載最新版本,截止今日(2012-06-11)最新版本爲0.8.0.

1. 如果是Maven構建項目的,直接在pom.xml 中添加如下內容:

1 <dependency>
2   <groupId>org.apache.thrift</groupId>
3   <artifactId>libthrift</artifactId>
4   <version>0.8.0</version>
5 </dependency>

2.如果自己編譯lib包,把下載的壓縮包解壓到X:盤,然後在X:\thrift-0.8.0\lib\java 目錄下運行ant進行自動編譯,會在X:\thrift-0.8.0\lib\java\build\ 目錄下看到編譯好的lib包:libthrift-0.8.0.jar

[三]、基本概念

1.數據類型

  • 基本類型:
    • bool:布爾值,true 或 false,對應 Java 的 boolean
    • byte:8 位有符號整數,對應 Java 的 byte
    • i16:16 位有符號整數,對應 Java 的 short
    • i32:32 位有符號整數,對應 Java 的 int
    • i64:64 位有符號整數,對應 Java 的 long
    • double:64 位浮點數,對應 Java 的 double
    • string:utf-8編碼的字符串,對應 Java 的 String
  • 結構體類型:
    • struct:定義公共的對象,類似於 C 語言中的結構體定義,在 Java 中是一個 JavaBean
  • 容器類型:
    • list:對應 Java 的 ArrayList
    • set:對應 Java 的 HashSet
    • map:對應 Java 的 HashMap
  • 異常類型:
    • exception:對應 Java 的 Exception
  • 服務類型:
    • service:對應服務的類

2.服務端編碼基本步驟:

  • 實現服務處理接口impl
  • 創建TProcessor
  • 創建TServerTransport
  • 創建TProtocol
  • 創建TServer
  • 啓動Server

3.客戶端編碼基本步驟:

  • 創建Transport
  • 創建TProtocol
  • 基於TTransport和TProtocol創建 Client
  • 調用Client的相應方法

4.數據傳輸協議

  • TBinaryProtocol : 二進制格式.
  • TCompactProtocol : 壓縮格式
  • TJSONProtocol : JSON格式
  • TSimpleJSONProtocol : 提供JSON只寫協議, 生成的文件很容易通過腳本語言解析

tips:客戶端和服務端的協議要一致

[四]、實例演示

1. thrift生成代碼

創建Thrift文件:G:\test\thrift\demoHello.thrift ,內容如下:

1 namespace java com.micmiu.thrift.demo
2  
3 service  HelloWorldService {
4   string sayHello(1:string username)
5 }

目錄結構如下:

G:\test\thrift>tree /F
卷 other 的文件夾 PATH 列表
卷序列號爲 D238-BE47
G:.
    demoHello.thrift
    demouser.thrift
    thrift-0.8.0.exe

沒有子文件夾

thrift-0.8.0.exe 是官網提供的windows下編譯工具,運用這個工具生成相關代碼:

1 thrift-0.8.0.exe -r -gen java ./demoHello.thrift

生成後的目錄結構如下:

G:\test\thrift>tree /F
卷 other 的文件夾 PATH 列表
卷序列號爲 D238-BE47
G:.
│  demoHello.thrift
│  demouser.thrift
│  thrift-0.8.0.exe
│
└─gen-java
    └─com
        └─micmiu
            └─thrift
                └─demo
                        HelloWorldService.java

將生成的HelloWorldService.java 文件copy到自己測試的工程中,我的工程是用maven構建的,故在pom.xml中增加如下內容:

1 <dependency>
2     <groupId>org.apache.thrift</groupId>
3     <artifactId>libthrift</artifactId>
4     <version>0.8.0</version>
5 </dependency>
6 <dependency>
7     <groupId>org.slf4j</groupId>
8     <artifactId>slf4j-log4j12</artifactId>
9     <version>1.5.8</version>
10 </dependency>

2. 實現接口Iface

java代碼:HelloWorldImpl.java

1 package com.micmiu.thrift.demo;
2  
3 import org.apache.thrift.TException;
4  
5 /**
7  *
8  * @author Michael
9  *
10  */
11 public class HelloWorldImpl implements HelloWorldService.Iface {
12  
13     public HelloWorldImpl() {
14     }
15  
16     @Override
17     public String sayHello(String username) throws TException {
18         return "Hi," + username + " welcome to my blog www.micmiu.com";
19     }
20  
21 }

3.TSimpleServer服務端

簡單的單線程服務模型,一般用於測試。

編寫服務端server代碼:HelloServerDemo.java

1 package com.micmiu.thrift.demo;
2  
3 import org.apache.thrift.TProcessor;
4 import org.apache.thrift.protocol.TBinaryProtocol;
5 import org.apache.thrift.protocol.TCompactProtocol;
6 import org.apache.thrift.protocol.TJSONProtocol;
7 import org.apache.thrift.protocol.TSimpleJSONProtocol;
8 import org.apache.thrift.server.TServer;
9 import org.apache.thrift.server.TSimpleServer;
10 import org.apache.thrift.transport.TServerSocket;
11  
12 /**
13  * blog http://www.micmiu.com
14  *
15  * @author Michael
16  *
17  */
18 public class HelloServerDemo {
19     public static final int SERVER_PORT = 8090;
20  
21     public void startServer() {
22         try {
23             System.out.println("HelloWorld TSimpleServer start ....");
24  
25             TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(
26                     new HelloWorldImpl());
27             // HelloWorldService.Processor<HelloWorldService.Iface> tprocessor =
28             // new HelloWorldService.Processor<HelloWorldService.Iface>(
29             // new HelloWorldImpl());
30  
31             // 簡單的單線程服務模型,一般用於測試
32             TServerSocket serverTransport = new TServerSocket(SERVER_PORT);
33             TServer.Args tArgs = new TServer.Args(serverTransport);
34             tArgs.processor(tprocessor);
35             tArgs.protocolFactory(new TBinaryProtocol.Factory());
36             // tArgs.protocolFactory(new TCompactProtocol.Factory());
37             // tArgs.protocolFactory(new TJSONProtocol.Factory());
38             TServer server = new TSimpleServer(tArgs);
39             server.serve();
40  
41         } catch (Exception e) {
42             System.out.println("Server start error!!!");
43             e.printStackTrace();
44         }
45     }
46  
47     /**
48      * @param args
49      */
50     public static void main(String[] args) {
51         HelloServerDemo server = new HelloServerDemo();
52         server.startServer();
53     }
54  
55 }

編寫客戶端Client代碼:HelloClientDemo.java

1 package com.micmiu.thrift.demo;
2  
3 import org.apache.thrift.TException;
4 import org.apache.thrift.protocol.TBinaryProtocol;
5 import org.apache.thrift.protocol.TCompactProtocol;
6 import org.apache.thrift.protocol.TJSONProtocol;
7 import org.apache.thrift.protocol.TProtocol;
8 import org.apache.thrift.transport.TSocket;
9 import org.apache.thrift.transport.TTransport;
10 import org.apache.thrift.transport.TTransportException;
11  
12 /**
13  * blog http://www.micmiu.com
14  *
15  * @author Michael
16  *
17  */
18 public class HelloClientDemo {
19  
20     public static final String SERVER_IP = "localhost";
21     public static final int SERVER_PORT = 8090;
22     public static final int TIMEOUT = 30000;
23  
24     /**
25      *
26      * @param userName
27      */
28     public void startClient(String userName) {
29         TTransport transport = null;
30         try {
31             transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT);
32             // 協議要和服務端一致
33             TProtocol protocol = new TBinaryProtocol(transport);
34             // TProtocol protocol = new TCompactProtocol(transport);
35             // TProtocol protocol = new TJSONProtocol(transport);
36             HelloWorldService.Client client = new HelloWorldService.Client(
37                     protocol);
38             transport.open();
39             String result = client.sayHello(userName);
40             System.out.println("Thrify client result =: " + result);
41         } catch (TTransportException e) {
42             e.printStackTrace();
43         } catch (TException e) {
44             e.printStackTrace();
45         } finally {
46             if (null != transport) {
47                 transport.close();
48             }
49         }
50     }
51  
52     /**
53      * @param args
54      */
55     public static void main(String[] args) {
56         HelloClientDemo client = new HelloClientDemo();
57         client.startClient("Michael");
58  
59     }
60  
61 }

先運行服務端程序,日誌如下:

HelloWorld TSimpleServer start ....

再運行客戶端調用程序,日誌如下:

Thrify client result =: Hi,Michael welcome to my blog www.micmiu.com

測試成功,和預期的返回信息一致。

4.TThreadPoolServer 服務模型

線程池服務模型,使用標準的阻塞式IO,預先創建一組線程處理請求。

編寫服務端代碼:HelloServerDemo.java

1 package com.micmiu.thrift.demo;
2  
3 import org.apache.thrift.TProcessor;
4 import org.apache.thrift.protocol.TBinaryProtocol;
5 import org.apache.thrift.server.TServer;
6 import org.apache.thrift.server.TThreadPoolServer;
7 import org.apache.thrift.transport.TServerSocket;
8  
9 /**
10  * blog http://www.micmiu.com
11  *
12  * @author Michael
13  *
14  */
15 public class HelloServerDemo {
16     public static final int SERVER_PORT = 8090;
17  
18     public void startServer() {
19         try {
20             System.out.println("HelloWorld TThreadPoolServer start ....");
21  
22             TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(
23                     new HelloWorldImpl());
24  
25              TServerSocket serverTransport = new TServerSocket(SERVER_PORT);
26              TThreadPoolServer.Args ttpsArgs = new TThreadPoolServer.Args(
27              serverTransport);
28              ttpsArgs.processor(tprocessor);
29              ttpsArgs.protocolFactory(new TBinaryProtocol.Factory());
30  
31             // 線程池服務模型,使用標準的阻塞式IO,預先創建一組線程處理請求。
32              TServer server = new TThreadPoolServer(ttpsArgs);
33              server.serve();
34  
35         } catch (Exception e) {
36             System.out.println("Server start error!!!");
37             e.printStackTrace();
38         }
39     }
40  
41     /**
42      * @param args
43      */
44     public static void main(String[] args) {
45         HelloServerDemo server = new HelloServerDemo();
46         server.startServer();
47     }
48  
49 }

客戶端Client代碼和之前的一樣,只要數據傳輸的協議一致即可,客戶端測試成功,結果如下:

Thrify client result =: Hi,Michael welcome to my blog www.micmiu.com

5.TNonblockingServer 服務模型

使用非阻塞式IO,服務端和客戶端需要指定 TFramedTransport 數據傳輸的方式。

編寫服務端代碼:HelloServerDemo.java

1 package com.micmiu.thrift.demo;
2  
3 import org.apache.thrift.TProcessor;
4 import org.apache.thrift.protocol.TCompactProtocol;
5 import org.apache.thrift.server.TNonblockingServer;
6 import org.apache.thrift.server.TServer;
7 import org.apache.thrift.transport.TFramedTransport;
8 import org.apache.thrift.transport.TNonblockingServerSocket;
9  
10 /**
11  * blog http://www.micmiu.com
12  *
13  * @author Michael
14  *
15  */
16 public class HelloServerDemo {
17     public static final int SERVER_PORT = 8090;
18  
19     public void startServer() {
20         try {
21             System.out.println("HelloWorld TNonblockingServer start ....");
22  
23             TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(
24                     new HelloWorldImpl());
25  
26             TNonblockingServerSocket tnbSocketTransport = new TNonblockingServerSocket(
27                     SERVER_PORT);
28             TNonblockingServer.Args tnbArgs = new TNonblockingServer.Args(
29                     tnbSocketTransport);
30             tnbArgs.processor(tprocessor);
31             tnbArgs.transportFactory(new TFramedTransport.Factory());
32             tnbArgs.protocolFactory(new TCompactProtocol.Factory());
33  
34             // 使用非阻塞式IO,服務端和客戶端需要指定TFramedTransport數據傳輸的方式
35             TServer server = new TNonblockingServer(tnbArgs);
36             server.serve();
37  
38         } catch (Exception e) {
39             System.out.println("Server start error!!!");
40             e.printStackTrace();
41         }
42     }
43  
44     /**
45      * @param args
46      */
47     public static void main(String[] args) {
48         HelloServerDemo server = new HelloServerDemo();
49         server.startServer();
50     }
51  
52 }

編寫客戶端代碼:HelloClientDemo.java

1 package com.micmiu.thrift.demo;
2  
3 import org.apache.thrift.TException;
4 import org.apache.thrift.protocol.TCompactProtocol;
5 import org.apache.thrift.protocol.TProtocol;
6 import org.apache.thrift.transport.TFramedTransport;
7 import org.apache.thrift.transport.TSocket;
8 import org.apache.thrift.transport.TTransport;
9 import org.apache.thrift.transport.TTransportException;
10  
11 /**
12  * blog http://www.micmiu.com
13  *
14  * @author Michael
15  *
16  */
17 public class HelloClientDemo {
18  
19     public static final String SERVER_IP = "localhost";
20     public static final int SERVER_PORT = 8090;
21     public static final int TIMEOUT = 30000;
22  
23     /**
24      *
25      * @param userName
26      */
27     public void startClient(String userName) {
28         TTransport transport = null;
29         try {
30             transport = new TFramedTransport(new TSocket(SERVER_IP,
31                     SERVER_PORT, TIMEOUT));
32             // 協議要和服務端一致
33             TProtocol protocol = new TCompactProtocol(transport);
34             HelloWorldService.Client client = new HelloWorldService.Client(
35                     protocol);
36             transport.open();
37             String result = client.sayHello(userName);
38             System.out.println("Thrify client result =: " + result);
39         } catch (TTransportException e) {
40             e.printStackTrace();
41         } catch (TException e) {
42             e.printStackTrace();
43         } finally {
44             if (null != transport) {
45                 transport.close();
46             }
47         }
48     }
49  
50     /**
51      * @param args
52      */
53     public static void main(String[] args) {
54         HelloClientDemo client = new HelloClientDemo();
55         client.startClient("Michael");
56  
57     }
58  
59 }

客戶端的測試成功,結果如下:

Thrify client result =: Hi,Michael welcome to my blog www.micmiu.com

6.THsHaServer服務模型

半同步半異步的服務端模型,需要指定爲: TFramedTransport 數據傳輸的方式。

編寫服務端代碼:HelloServerDemo.java

1 package com.micmiu.thrift.demo;
2  
3 import org.apache.thrift.TProcessor;
4 import org.apache.thrift.protocol.TBinaryProtocol;
5 import org.apache.thrift.protocol.TCompactProtocol;
6 import org.apache.thrift.server.THsHaServer;
7 import org.apache.thrift.server.TNonblockingServer;
8 import org.apache.thrift.server.TServer;
9 import org.apache.thrift.server.TSimpleServer;
10 import org.apache.thrift.server.TThreadPoolServer;
11 import org.apache.thrift.transport.TFramedTransport;
12 import org.apache.thrift.transport.TNonblockingServerSocket;
13 import org.apache.thrift.transport.TServerSocket;
14  
15 /**
16  * blog http://www.micmiu.com
17  *
18  * @author Michael
19  *
20  */
21 public class HelloServerDemo {
22     public static final int SERVER_PORT = 8090;
23  
24     public void startServer() {
25         try {
26             System.out.println("HelloWorld THsHaServer start ....");
27  
28             TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(
29                     new HelloWorldImpl());
30  
31             TNonblockingServerSocket tnbSocketTransport = new TNonblockingServerSocket(
32                     SERVER_PORT);
33             THsHaServer.Args thhsArgs = new THsHaServer.Args(tnbSocketTransport);
34             thhsArgs.processor(tprocessor);
35             thhsArgs.transportFactory(new TFramedTransport.Factory());
36             thhsArgs.protocolFactory(new TBinaryProtocol.Factory());
37  
38             //半同步半異步的服務模型
39             TServer server = new THsHaServer(thhsArgs);
40             server.serve();
41  
42         } catch (Exception e) {
43             System.out.println("Server start error!!!");
44             e.printStackTrace();
45         }
46     }
47  
48     /**
49      * @param args
50      */
51     public static void main(String[] args) {
52         HelloServerDemo server = new HelloServerDemo();
53         server.startServer();
54     }
55  
56 }

客戶端代碼和上面 4 中的類似,只要注意傳輸協議一致以及指定傳輸方式爲TFramedTransport

7.異步客戶端

編寫服務端代碼:HelloServerDemo.java

1 package com.micmiu.thrift.demo;
2  
3 import org.apache.thrift.TProcessor;
4 import org.apache.thrift.protocol.TCompactProtocol;
5 import org.apache.thrift.server.TNonblockingServer;
6 import org.apache.thrift.server.TServer;
7 import org.apache.thrift.transport.TFramedTransport;
8 import org.apache.thrift.transport.TNonblockingServerSocket;
9  
10 /**
11  * blog http://www.micmiu.com
12  *
13  * @author Michael
14  *
15  */
16 public class HelloServerDemo {
17     public static final int SERVER_PORT = 8090;
18  
19     public void startServer() {
20         try {
21             System.out.println("HelloWorld TNonblockingServer start ....");
22  
23             TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(
24                     new HelloWorldImpl());
25  
26             TNonblockingServerSocket tnbSocketTransport = new TNonblockingServerSocket(
27                     SERVER_PORT);
28             TNonblockingServer.Args tnbArgs = new TNonblockingServer.Args(
29                     tnbSocketTransport);
30             tnbArgs.processor(tprocessor);
31             tnbArgs.transportFactory(new TFramedTransport.Factory());
32             tnbArgs.protocolFactory(new TCompactProtocol.Factory());
33  
34             // 使用非阻塞式IO,服務端和客戶端需要指定TFramedTransport數據傳輸的方式
35             TServer server = new TNonblockingServer(tnbArgs);
36             server.serve();
37  
38         } catch (Exception e) {
39             System.out.println("Server start error!!!");
40             e.printStackTrace();
41         }
42     }
43  
44     /**
45      * @param args
46      */
47     public static void main(String[] args) {
48         HelloServerDemo server = new HelloServerDemo();
49         server.startServer();
50     }
51  
52 }

編寫客戶端Client代碼:HelloAsynClientDemo.java

1 package com.micmiu.thrift.demo;
2  
3 import java.util.concurrent.CountDownLatch;
4 import java.util.concurrent.TimeUnit;
5  
6 import org.apache.thrift.TException;
7 import org.apache.thrift.async.AsyncMethodCallback;
8 import org.apache.thrift.async.TAsyncClientManager;
9 import org.apache.thrift.protocol.TCompactProtocol;
10 import org.apache.thrift.protocol.TProtocolFactory;
11 import org.apache.thrift.transport.TNonblockingSocket;
12 import org.apache.thrift.transport.TNonblockingTransport;
13  
14 import com.micmiu.thrift.demo.HelloWorldService.AsyncClient.sayHello_call;
15  
16 /**
17  * blog http://www.micmiu.com
18  *
19  * @author Michael
20  *
21  */
22 public class HelloAsynClientDemo {
23  
24     public static final String SERVER_IP = "localhost";
25     public static final int SERVER_PORT = 8090;
26     public static final int TIMEOUT = 30000;
27  
28     /**
29      *
30      * @param userName
31      */
32     public void startClient(String userName) {
33         try {
34             TAsyncClientManager clientManager = new TAsyncClientManager();
35             TNonblockingTransport transport = new TNonblockingSocket(SERVER_IP,
36                     SERVER_PORT, TIMEOUT);
37  
38             TProtocolFactory tprotocol = new TCompactProtocol.Factory();
39             HelloWorldService.AsyncClient asyncClient = new HelloWorldService.AsyncClient(
40                     tprotocol, clientManager, transport);
41             System.out.println("Client start .....");
42  
43             CountDownLatch latch = new CountDownLatch(1);
44             AsynCallback callBack = new AsynCallback(latch);
45             System.out.println("call method sayHello start ...");
46             asyncClient.sayHello(userName, callBack);
47             System.out.println("call method sayHello .... end");
48             boolean wait = latch.await(30, TimeUnit.SECONDS);
49             System.out.println("latch.await =:" + wait);
50         } catch (Exception e) {
51             e.printStackTrace();
52         }
53         System.out.println("startClient end.");
54     }
55  
56     public class AsynCallback implements AsyncMethodCallback<sayHello_call> {
57         private CountDownLatch latch;
58  
59         public AsynCallback(CountDownLatch latch) {
60             this.latch = latch;
61         }
62  
63         @Override
64         public void onComplete(sayHello_call response) {
65             System.out.println("onComplete");
66             try {
67                 // Thread.sleep(1000L * 1);
68                 System.out.println("AsynCall result =:"
69                         + response.getResult().toString());
70             } catch (TException e) {
71                 e.printStackTrace();
72             } catch (Exception e) {
73                 e.printStackTrace();
74             } finally {
75                 latch.countDown();
76             }
77         }
78  
79         @Override
80         public void onError(Exception exception) {
81             System.out.println("onError :" + exception.getMessage());
82             latch.countDown();
83         }
84     }
85  
86     /**
87      * @param args
88      */
89     public static void main(String[] args) {
90         HelloAsynClientDemo client = new HelloAsynClientDemo();
91         client.startClient("Michael");
92  
93     }
94  
95 }

先運行服務程序,再運行客戶端程序,測試結果如下:

Client start .....
call method sayHello start ...
call method sayHello .... end
onComplete
AsynCall result =:Hi,Michael welcome to my blog www.micmiu.com
latch.await =:true
startClient end.

————

原創文章,轉載請註明: 轉載自micmiu – 軟件開發+生活點滴[ http://www.micmiu.com/ ]

本文鏈接地址: http://www.micmiu.com/soa/rpc/thrift-sample/


發佈了122 篇原創文章 · 獲贊 3 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章