一.什么是Thrift?
     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
  
   二、Thrift的基础
  基本类型:
  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:对应服务的类
   
   服务端编码基本步骤
     - 实现服务处理接口impl
- 创建TProcessor
- 创建TServerTransport
- 创建TProtocol
- 创建TServer
- 启动Server
客户端编码基本步骤
     - 创建Transport
- 创建TProtocol
- 基于TTransport和TProtocol创建Client
- 调用Client的相应方法
数据传输协议
     - TBinaryProtocol 二进制格式
- TCompactProtocol 压缩格式
- TJSONProtocol JSON格式
- TSimpleJSONProtocol 提供JSON只写协议,生成的文件很容易通过脚本语言解析
提示:客户端和服务端的协议要一致
   基本关键字
     - oneway  : 表示客户端调用服务器不关心服务器的返回值,不关心服务器程序是否执行完成
- void :  和oneway一样没有返回值,但是会确保服务器程序执行完成
- extends:继承,service之间可以通过extends继承
三、简单示例
  3.1基本配置
  到官网下载最新版本,截止今日(2016-04-23)最新版本为0.9.3
     - 如果是Maven构建项目的,直接在pom.xml 中添加如下内容:
<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>
     - 也可以手动配置jar包,在项目中添加如下jar包即可

    
  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
   
  四、注意事项
  ①thrift服务调用也可以通过异步方式,需要继承AsyncIface,并且实现TNonblockingServer模型
  ②命令中的 -gen的值确定生成不同语言的代码,如-gen php,-gen java
  ③thrift需要各种语言的支持库或者虚拟机才能生成代码,因此需要下载不同的虚拟机SDK,配置相应的环境变量。