Thrift是一個軟件框架,用來進行可擴展且跨語言的服務的開發。它結合了功能強大的軟件堆棧和代碼生成引擎,以構建在 C++、Java、Python、PHP、Ruby、Erlang、Perl、Haskell、C#、Cocoa、JavaScript、Node.js、Smalltalk、and OCaml 等等編程語言間無縫結合的、高效的服務。php
Thrift最初由facebook開發,07年四月開放源碼,08年5月進入Apache孵化器。Thrift容許你定義一個簡單的定義文件中的數據類型和服務接口。以做爲輸入文件,編譯器生成代碼用來方便地生成RPC客戶端和服務器通訊的無縫跨編程語言。java
官網地址:thrift.apache.orgc++
基本類型:apache
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:對應服務的類
提示:客戶端和服務端的協議要一致編程語言
3.1基本配置ide
到官網下載最新版本,截止今日(2016-04-23)最新版本爲0.9.3
<dependency> <groupId>org.apache.thrift</groupId> <artifactId>libthrift</artifactId> <version>0.9.3</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.5</version> </dependency>
3.2 下載thrift而且配置環境變量
下載thrift 工具,將thrift-x.x.x.exe修改完thrift.exe,而且將次程序所在位置添加到path環境變量中。
3.3 生成簡單示例
shared.thrift
namespace cpp com.itest.thrift.shared #c++中的命名空間 namespace java com.itest.thrift.shared #java 包名 namespace php com.itest.thrift.shared #php命名空間 struct SharedStruct { 1: i32 key 2: string value } service SharedService { SharedStruct getStruct(1: i32 key) }
tutorial.thrift
include "shared.thrift" #引入shared.thrift namespace cpp com.itest.thrift.service namespace java com.itest.thrift.service namespace php com.itest.thrift.service /** * 定義c風格的數據類型 * */ typedef i32 MyInteger /** * 定義常量 * */ const i32 INT32CONSTANT = 9853 const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'} /** * * 定義枚舉 */ enum Operation { //php默認不支持枚舉,但這裏也會經過其餘方式生成php枚舉 ADD = 1, SUBTRACT = 2, MULTIPLY = 3, DIVIDE = 4 } /** * * 定義結構體,在php和java中生成bean,在c++中是結構體 */ struct Work { 1: i32 num1 = 0, 2: i32 num2, 3: Operation op, 4: optional string comment, } /** * 定義異常類型,擴展性很強 */ exception InvalidOperation { 1: i32 whatOp, 2: string why } /** * 定義服務,這裏也能夠繼承其餘服務 */ service Calculator extends shared.SharedService { /** * 定義服務方法 */ void ping(), i32 add(1:i32 num1, 2:i32 num2), i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch), /** * 此方法表示客戶端只發送請求,不關心程序的執行和執行結果,和void不一樣,void須要確認程序執行結束 */ oneway void zip() }
3.4生成代碼
執行以下命令(更多命令,請執行 thrift --help 查詢)
thrift -o ./ -out ./ -r -gen java tutorial.thrift
將生成的代碼添加到項目中,以下:
3.4 實現接口Iface
package com.itest.thrift.handler; import java.util.HashMap; import com.itest.thrift.service.InvalidOperation; import com.itest.thrift.service.Work; import com.itest.thrift.service.Calculator; import com.itest.thrift.shared.SharedStruct; // Generated code public class CalculatorHandler implements Calculator.Iface { private HashMap<Integer,SharedStruct> log; public CalculatorHandler() { log = new HashMap<Integer, SharedStruct>(); } public void ping() { System.out.println("ping()"); } public int add(int n1, int n2) { System.out.println("add(" + n1 + "," + n2 + ")"); return n1 + n2; } public int calculate(int logid, Work work) throws InvalidOperation { System.out.println("calculate(" + logid + ", {" + work.op + "," + work.num1 + "," + work.num2 + "})"); int val = 0; switch (work.op) { case ADD: val = work.num1 + work.num2; break; case SUBTRACT: val = work.num1 - work.num2; break; case MULTIPLY: val = work.num1 * work.num2; break; case DIVIDE: if (work.num2 == 0) { InvalidOperation io = new InvalidOperation(); io.whatOp = work.op.getValue(); io.why = "Cannot divide by 0"; throw io; } val = work.num1 / work.num2; break; default: InvalidOperation io = new InvalidOperation(); io.whatOp = work.op.getValue(); io.why = "Unknown operation"; throw io; } SharedStruct entry = new SharedStruct(); entry.key = logid; entry.value = Integer.toString(val); log.put(logid, entry); return val; } public SharedStruct getStruct(int key) { System.out.println("getStruct(" + key + ")"); return log.get(key); } public void zip() { System.out.println("zip()"); } }
3.5發佈服務
package com.iuap.thirft.itest; import org.apache.thrift.server.TServer; import org.apache.thrift.server.TServer.Args; import org.apache.thrift.server.TSimpleServer; import org.apache.thrift.transport.TServerSocket; import org.apache.thrift.transport.TServerTransport; import com.itest.thrift.handler.CalculatorHandler; import com.itest.thrift.service.Calculator; // Generated code public class JavaServer { public static CalculatorHandler handler; @SuppressWarnings("rawtypes") public static Calculator.Processor processor; @SuppressWarnings("rawtypes") public static void main(String [] args) { try { handler = new CalculatorHandler(); processor = new Calculator.Processor(handler); Runnable simple = new Runnable() { public void run() { simple(processor); } }; new Thread(simple).start(); } catch (Exception x) { x.printStackTrace(); } } public static void simple(@SuppressWarnings("rawtypes") Calculator.Processor processor) { try { TServerTransport serverTransport = new TServerSocket(9090); TServer server = new TSimpleServer(new Args(serverTransport).processor(processor)); System.out.println("Starting the simple server..."); server.serve(); } catch (Exception e) { e.printStackTrace(); } } }
3.6調用服務
package com.iuap.thirft.itest; 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 com.itest.thrift.service.Calculator; import com.itest.thrift.service.InvalidOperation; import com.itest.thrift.service.Operation; import com.itest.thrift.service.Work; import com.itest.thrift.shared.SharedStruct; public class JavaClient { public static void main(String [] args) { try { TTransport transport; // if (args[0].contains("simple")) { transport = new TSocket("localhost", 9090); transport.open(); /* } else { TSSLTransportParameters params = new TSSLTransportParameters(); params.setTrustStore("../../lib/java/test/.truststore", "thrift", "SunX509", "JKS"); transport = TSSLTransportFactory.getClientSocket("localhost", 9091, 0, params); }*/ TProtocol protocol = new TBinaryProtocol(transport); Calculator.Client client = new Calculator.Client(protocol); perform(client); transport.close(); } catch (TException x) { x.printStackTrace(); } } private static void perform(Calculator.Client client) throws TException { client.ping(); System.out.println("ping()"); int sum = client.add(1,1); System.out.println("1+1=" + sum); Work work = new Work(); work.op = Operation.DIVIDE; work.num1 = 1; work.num2 = 0; try { int quotient = client.calculate(1, work); System.out.println("Whoa we can divide by 0"); } catch (InvalidOperation io) { System.out.println("Invalid operation: " + io.why); } work.op = Operation.SUBTRACT; work.num1 = 15; work.num2 = 10; try { int diff = client.calculate(1, work); System.out.println("15-10=" + diff); } catch (InvalidOperation io) { System.out.println("Invalid operation: " + io.why); } client.zip(); SharedStruct log = client.getStruct(1); System.out.println("Check log: " + log.value); } }
3.7執行結果
服務器端
Starting the simple server... ping() add(1,1) calculate(1, {DIVIDE,1,0}) calculate(1, {SUBTRACT,15,10}) zip() getStruct(1) ping() add(1,1) calculate(1, {DIVIDE,1,0}) calculate(1, {SUBTRACT,15,10}) zip() getStruct(1)
客戶端
ping() 1+1=2 Invalid operation: Cannot divide by 0 15-10=5 Check log: 5
4、注意事項
①thrift服務調用也能夠經過異步方式,須要繼承AsyncIface,而且實現TNonblockingServer模型
②命令中的 -gen的值肯定生成不一樣語言的代碼,如-gen php,-gen java
③thrift須要各類語言的支持庫或者虛擬機才能生成代碼,所以須要下載不一樣的虛擬機SDK,配置相應的環境變量。