目錄:
- 概述
- 下載配置
- 基本概念
- 數據類(lèi)型
- 服務(wù)端編碼基本步驟
- 客戶(hù)端編碼基本步驟
- 數據傳輸協(xié)議
- 實(shí)例演示(java)
- thrift生成代碼
- 實(shí)現接口Iface
- TSimpleServer服務(wù)模型
- TThreadPoolServer 服務(wù)模型
- TNonblockingServer 服務(wù)模型
- THsHaServer服務(wù)模型
- 異步客戶(hù)端
[一]、概述
Thrift是一個(gè)軟件框架,用來(lái)進(jìn)行可擴展且跨語(yǔ)言的服務(wù)的開(kāi)發(fā)。它結合了功能強大的軟件堆棧和代碼生成引擎,以構建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 等等編程語(yǔ)言間無(wú)縫結合的、高效的服務(wù)。
Thrift最初由facebook開(kāi)發(fā),07年四月開(kāi)放源碼,08年5月進(jìn)入apache孵化器。thrift允許你定義一個(gè)簡(jiǎn)單的定義文件中的數據類(lèi)型和服務(wù)接口。以作為輸入文件,編譯器生成代碼用來(lái)方便地生成RPC客戶(hù)端和服務(wù)器通信的無(wú)縫跨編程語(yǔ)言。
官網(wǎng)地址:thrift.apache.org
推薦值得一看的文章:
[二]、下載配置
到官網(wǎng)下載最新版本,截止今日(2012-06-11)最新版本為0.8.0.
1. 如果是Maven構建項目的,直接在pom.xml 中添加如下內容:
2 | <groupId>org.apache.thrift</groupId> |
3 | <artifactId>libthrift</artifactId> |
4 | <version>0.8.0</version> |
2.如果自己編譯lib包,把下載的壓縮包解壓到X:盤(pán),然后在X:\thrift-0.8.0\lib\java 目錄下運行ant進(jìn)行自動(dòng)編譯,會(huì )在X:\thrift-0.8.0\lib\java\build\ 目錄下看到編譯好的lib包:libthrift-0.8.0.jar
[三]、基本概念
1.數據類(lèi)型
- 基本類(lèi)型:
- bool:布爾值,true 或 false,對應 Java 的 boolean
- byte:8 位有符號整數,對應 Java 的 byte
- i16:16 位有符號整數,對應 Java 的 short
- i32:32 位有符號整數,對應 Java 的 int
- i64:64 位有符號整數,對應 Java 的 long
- double:64 位浮點(diǎn)數,對應 Java 的 double
- string:utf-8編碼的字符串,對應 Java 的 String
- 結構體類(lèi)型:
- struct:定義公共的對象,類(lèi)似于 C 語(yǔ)言中的結構體定義,在 Java 中是一個(gè) JavaBean
- 容器類(lèi)型:
- list:對應 Java 的 ArrayList
- set:對應 Java 的 HashSet
- map:對應 Java 的 HashMap
- 異常類(lèi)型:
- exception:對應 Java 的 Exception
- 服務(wù)類(lèi)型:
2.服務(wù)端編碼基本步驟:
- 實(shí)現服務(wù)處理接口impl
- 創(chuàng )建TProcessor
- 創(chuàng )建TServerTransport
- 創(chuàng )建TProtocol
- 創(chuàng )建TServer
- 啟動(dòng)Server
3.客戶(hù)端編碼基本步驟:
- 創(chuàng )建Transport
- 創(chuàng )建TProtocol
- 基于TTransport和TProtocol創(chuàng )建 Client
- 調用Client的相應方法
4.數據傳輸協(xié)議
- TBinaryProtocol : 二進(jìn)制格式.
- TCompactProtocol : 壓縮格式
- TJSONProtocol : JSON格式
- TSimpleJSONProtocol : 提供JSON只寫(xiě)協(xié)議, 生成的文件很容易通過(guò)腳本語(yǔ)言解析
tips:客戶(hù)端和服務(wù)端的協(xié)議要一致
[四]、實(shí)例演示
1. thrift生成代碼
創(chuàng )建Thrift文件:G:\test\thrift\demoHello.thrift ,內容如下:
1 | namespace java com.micmiu.thrift.demo |
3 | service HelloWorldService { |
4 | string sayHello(1:string username) |
目錄結構如下:
G:\test\thrift>tree /F卷 other 的文件夾 PATH 列表卷序列號為 D238-BE47G:. demoHello.thrift demouser.thrift thrift-0.8.0.exe沒(méi)有子文件夾
thrift-0.8.0.exe 是官網(wǎng)提供的windows下編譯工具,運用這個(gè)工具生成相關(guān)代碼:
1 | thrift-0.8.0.exe -r -gen java ./demoHello.thrift |
生成后的目錄結構如下:
G:\test\thrift>tree /F卷 other 的文件夾 PATH 列表卷序列號為 D238-BE47G:.│ demoHello.thrift│ demouser.thrift│ thrift-0.8.0.exe│└─gen-java └─com └─micmiu └─thrift └─demo HelloWorldService.java
將生成的HelloWorldService.java 文件copy到自己測試的工程中,我的工程是用maven構建的,故在pom.xml中增加如下內容:
2 | <groupId>org.apache.thrift</groupId> |
3 | <artifactId>libthrift</artifactId> |
4 | <version>0.8.0</version> |
7 | <groupId>org.slf4j</groupId> |
8 | <artifactId>slf4j-log4j12</artifactId> |
9 | <version>1.5.8</version> |
2. 實(shí)現接口Iface
java代碼:HelloWorldImpl.java
1 | package com.micmiu.thrift.demo; |
3 | import org.apache.thrift.TException; |
11 | public class HelloWorldImpl implements HelloWorldService.Iface { |
13 | public HelloWorldImpl() { |
17 | public String sayHello(String username) throws TException { |
18 | return "Hi," + username + " welcome to my blog www.micmiu.com"; |
3.TSimpleServer服務(wù)端
簡(jiǎn)單的單線(xiàn)程服務(wù)模型,一般用于測試。
編寫(xiě)服務(wù)端server代碼:HelloServerDemo.java
1 | package com.micmiu.thrift.demo; |
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; |
18 | public class HelloServerDemo { |
19 | public static final int SERVER_PORT = 8090; |
21 | public void startServer() { |
23 | System.out.println("HelloWorld TSimpleServer start ...."); |
25 | TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>( |
26 | new HelloWorldImpl()); |
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()); |
38 | TServer server = new TSimpleServer(tArgs); |
41 | } catch (Exception e) { |
42 | System.out.println("Server start error!!!"); |
50 | public static void main(String[] args) { |
51 | HelloServerDemo server = new HelloServerDemo(); |
編寫(xiě)客戶(hù)端Client代碼:HelloClientDemo.java
1 | package com.micmiu.thrift.demo; |
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; |
18 | public class HelloClientDemo { |
20 | public static final String SERVER_IP = "localhost"; |
21 | public static final int SERVER_PORT = 8090; |
22 | public static final int TIMEOUT = 30000; |
28 | public void startClient(String userName) { |
29 | TTransport transport = null; |
31 | transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT); |
33 | TProtocol protocol = new TBinaryProtocol(transport); |
36 | HelloWorldService.Client client = new HelloWorldService.Client( |
39 | String result = client.sayHello(userName); |
40 | System.out.println("Thrify client result =: " + result); |
41 | } catch (TTransportException e) { |
43 | } catch (TException e) { |
46 | if (null != transport) { |
55 | public static void main(String[] args) { |
56 | HelloClientDemo client = new HelloClientDemo(); |
57 | client.startClient("Michael"); |
先運行服務(wù)端程序,日志如下:
HelloWorld TSimpleServer start ....
再運行客戶(hù)端調用程序,日志如下:
Thrify client result =: Hi,Michael welcome to my blog www.micmiu.com
測試成功,和預期的返回信息一致。
4.TThreadPoolServer 服務(wù)模型
線(xiàn)程池服務(wù)模型,使用標準的阻塞式IO,預先創(chuàng )建一組線(xiàn)程處理請求。
編寫(xiě)服務(wù)端代碼:HelloServerDemo.java
1 | package com.micmiu.thrift.demo; |
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; |
15 | public class HelloServerDemo { |
16 | public static final int SERVER_PORT = 8090; |
18 | public void startServer() { |
20 | System.out.println("HelloWorld TThreadPoolServer start ...."); |
22 | TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>( |
23 | new HelloWorldImpl()); |
25 | TServerSocket serverTransport = new TServerSocket(SERVER_PORT); |
26 | TThreadPoolServer.Args ttpsArgs = new TThreadPoolServer.Args( |
28 | ttpsArgs.processor(tprocessor); |
29 | ttpsArgs.protocolFactory(new TBinaryProtocol.Factory()); |
32 | TServer server = new TThreadPoolServer(ttpsArgs); |
35 | } catch (Exception e) { |
36 | System.out.println("Server start error!!!"); |
44 | public static void main(String[] args) { |
45 | HelloServerDemo server = new HelloServerDemo(); |
客戶(hù)端Client代碼和之前的一樣,只要數據傳輸的協(xié)議一致即可,客戶(hù)端測試成功,結果如下:
Thrify client result =: Hi,Michael welcome to my blog www.micmiu.com
5.TNonblockingServer 服務(wù)模型
使用非阻塞式IO,服務(wù)端和客戶(hù)端需要指定 TFramedTransport 數據傳輸的方式。
編寫(xiě)服務(wù)端代碼:HelloServerDemo.java
1 | package com.micmiu.thrift.demo; |
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; |
16 | public class HelloServerDemo { |
17 | public static final int SERVER_PORT = 8090; |
19 | public void startServer() { |
21 | System.out.println("HelloWorld TNonblockingServer start ...."); |
23 | TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>( |
24 | new HelloWorldImpl()); |
26 | TNonblockingServerSocket tnbSocketTransport = new TNonblockingServerSocket( |
28 | TNonblockingServer.Args tnbArgs = new TNonblockingServer.Args( |
30 | tnbArgs.processor(tprocessor); |
31 | tnbArgs.transportFactory(new TFramedTransport.Factory()); |
32 | tnbArgs.protocolFactory(new TCompactProtocol.Factory()); |
35 | TServer server = new TNonblockingServer(tnbArgs); |
38 | } catch (Exception e) { |
39 | System.out.println("Server start error!!!"); |
47 | public static void main(String[] args) { |
48 | HelloServerDemo server = new HelloServerDemo(); |
編寫(xiě)客戶(hù)端代碼:HelloClientDemo.java
1 | package com.micmiu.thrift.demo; |
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; |
17 | public class HelloClientDemo { |
19 | public static final String SERVER_IP = "localhost"; |
20 | public static final int SERVER_PORT = 8090; |
21 | public static final int TIMEOUT = 30000; |
27 | public void startClient(String userName) { |
28 | TTransport transport = null; |
30 | transport = new TFramedTransport(new TSocket(SERVER_IP, |
31 | SERVER_PORT, TIMEOUT)); |
33 | TProtocol protocol = new TCompactProtocol(transport); |
34 | HelloWorldService.Client client = new HelloWorldService.Client( |
37 | String result = client.sayHello(userName); |
38 | System.out.println("Thrify client result =: " + result); |
39 | } catch (TTransportException e) { |
41 | } catch (TException e) { |
44 | if (null != transport) { |
53 | public static void main(String[] args) { |
54 | HelloClientDemo client = new HelloClientDemo(); |
55 | client.startClient("Michael"); |
客戶(hù)端的測試成功,結果如下:
Thrify client result =: Hi,Michael welcome to my blog www.micmiu.com
6.THsHaServer服務(wù)模型
半同步半異步的服務(wù)端模型,需要指定為: TFramedTransport 數據傳輸的方式。
編寫(xiě)服務(wù)端代碼:HelloServerDemo.java
1 | package com.micmiu.thrift.demo; |
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; |
21 | public class HelloServerDemo { |
22 | public static final int SERVER_PORT = 8090; |
24 | public void startServer() { |
26 | System.out.println("HelloWorld THsHaServer start ...."); |
28 | TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>( |
29 | new HelloWorldImpl()); |
31 | TNonblockingServerSocket tnbSocketTransport = new TNonblockingServerSocket( |
33 | THsHaServer.Args thhsArgs = new THsHaServer.Args(tnbSocketTransport); |
34 | thhsArgs.processor(tprocessor); |
35 | thhsArgs.transportFactory(new TFramedTransport.Factory()); |
36 | thhsArgs.protocolFactory(new TBinaryProtocol.Factory()); |
39 | TServer server = new THsHaServer(thhsArgs); |
42 | } catch (Exception e) { |
43 | System.out.println("Server start error!!!"); |
51 | public static void main(String[] args) { |
52 | HelloServerDemo server = new HelloServerDemo(); |
客戶(hù)端代碼和上面 4 中的類(lèi)似,只要注意傳輸協(xié)議一致以及指定傳輸方式為TFramedTransport。
7.異步客戶(hù)端
編寫(xiě)服務(wù)端代碼:HelloServerDemo.java
1 | package com.micmiu.thrift.demo; |
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; |
16 | public class HelloServerDemo { |
17 | public static final int SERVER_PORT = 8090; |
19 | public void startServer() { |
21 | System.out.println("HelloWorld TNonblockingServer start ...."); |
23 | TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>( |
24 | new HelloWorldImpl()); |
26 | TNonblockingServerSocket tnbSocketTransport = new TNonblockingServerSocket( |
28 | TNonblockingServer.Args tnbArgs = new TNonblockingServer.Args( |
30 | tnbArgs.processor(tprocessor); |
31 | tnbArgs.transportFactory(new TFramedTransport.Factory()); |
32 | tnbArgs.protocolFactory(new TCompactProtocol.Factory()); |
35 | TServer server = new TNonblockingServer(tnbArgs); |
38 | } catch (Exception e) { |
39 | System.out.println("Server start error!!!"); |
47 | public static void main(String[] args) { |
48 | HelloServerDemo server = new HelloServerDemo(); |
編寫(xiě)客戶(hù)端Client代碼:HelloAsynClientDemo.java
1 | package com.micmiu.thrift.demo; |
3 | import java.util.concurrent.CountDownLatch; |
4 | import java.util.concurrent.TimeUnit; |
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; |
14 | import com.micmiu.thrift.demo.HelloWorldService.AsyncClient.sayHello_call; |
22 | public class HelloAsynClientDemo { |
24 | public static final String SERVER_IP = "localhost"; |
25 | public static final int SERVER_PORT = 8090; |
26 | public static final int TIMEOUT = 30000; |
32 | public void startClient(String userName) { |
34 | TAsyncClientManager clientManager = new TAsyncClientManager(); |
35 | TNonblockingTransport transport = new TNonblockingSocket(SERVER_IP, |
36 | SERVER_PORT, TIMEOUT); |
38 | TProtocolFactory tprotocol = new TCompactProtocol.Factory(); |
39 | HelloWorldService.AsyncClient asyncClient = new HelloWorldService.AsyncClient( |
40 | tprotocol, clientManager, transport); |
41 | System.out.println("Client start ....."); |
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) { |
53 | System.out.println("startClient end."); |
56 | public class AsynCallback implements AsyncMethodCallback<sayHello_call> { |
57 | private CountDownLatch latch; |
59 | public AsynCallback(CountDownLatch latch) { |
64 | public void onComplete(sayHello_call response) { |
65 | System.out.println("onComplete"); |
68 | System.out.println("AsynCall result =:" |
69 | + response.getResult().toString()); |
70 | } catch (TException e) { |
72 | } catch (Exception e) { |
80 | public void onError(Exception exception) { |
81 | System.out.println("onError :" + exception.getMessage()); |
89 | public static void main(String[] args) { |
90 | HelloAsynClientDemo client = new HelloAsynClientDemo(); |
91 | client.startClient("Michael"); |
先運行服務(wù)程序,再運行客戶(hù)端程序,測試結果如下:
Client start .....call method sayHello start ...call method sayHello .... endonCompleteAsynCall result =:Hi,Michael welcome to my blog www.micmiu.comlatch.await =:truestartClient end.