前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Thrift使用教程(Java版本)

Thrift使用教程(Java版本)

作者头像
孟君
发布2020-08-27 17:15:21
6.2K0
发布2020-08-27 17:15:21
举报

在之前的一篇博文一步步完成thrift rpc示例中,给出了一个使用thrift完成rpc的示例。

在本篇文章,我们会给出一个使用Thrift的基本教程。

Thrift简介

Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目。Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(目前支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),并由生成的代码负责RPC协议层和传输层的实现

Thrift协议栈

Thrift 客户端、服务端API架构如下图所示:

图片来自https://en.wikipedia.org/wiki/Apache_Thrift

Thrift的网络栈如下所示:

Transport

Transport层提供了一个简单的网络读写抽象层。这使得thrift底层的transport从系统其它部分(如:序列化/反序列化)解耦。以下是一些Transport接口提供的方法:

代码语言:javascript
复制
open
close
read
write
flush

更加详细方法如,

Thrift支持如下几种Transport:

在之前的一篇博文【一步一步完成thrift Java示例】中,给出了一个使用thrift完成rpc的示例。

在本篇博文,我们会给出一个使用Thrift的基本教程~

Thrift简介

Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目。Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(目前支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),并由生成的代码负责RPC协议层和传输层的实现

Thrift协议栈

Thrift 客户端、服务端API架构如下图所示:

图片来自https://en.wikipedia.org/wiki/Apache_Thrift

Thrift的网络栈如下所示:

Transport

Transport层提供了一个简单的网络读写抽象层。这使得thrift底层的transport从系统其它部分(如:序列化/反序列化)解耦。以下是一些Transport接口提供的方法:

代码语言:javascript
复制
open
close
read
write
flush

更加详细方法如,

Thrift支持如下几种Transport:

  • TIOStreamTransport和TSocket这两个类的结构对应着阻塞同步IO, TSocket封装了Socket接口
  • TNonblockingTrasnsort,TNonblockingSocket这两个类对应着非阻塞IO
  • TMemoryInputTransport封装了一个字节数组byte[]来做输入流的封装
  • TMemoryBuffer使用字节数组输出流ByteArrayOutputStream做输出流的封装
  • TFramedTransport则封装了TMemoryInputTransport做输入流,封装了TByteArryOutPutStream做输出流,作为内存读写缓冲区的一个封装。TFramedTransport的flush方法时,会先写4个字节的输出流的长度作为消息头,然后写消息体。和FrameBuffer的读消息对应起来。FrameBuffer对消息时,先读4个字节的长度,再读消息体
  • TFastFramedTransport是内存利用率更高的一个内存读写缓存区,它使用自动增长的byte[](不够长度才new),而不是每次都new一个byte[],提高了内存的使用率。其他和TFramedTransport一样,flush时也会写4个字节的消息头表示消息长度。

Protocol

Protocol抽象层定义了一种将内存中数据结构映射成可传输格式的机制。换句话说,Protocol定义了datatype怎样使用底层的Transport对自己进行编解码。因此,Protocol的实现要给出编码机制并负责对数据进行序列化。

Thrift支持如下几种protocols:

  • TBinaryProtocol : 二进制格式.
  • TCompactProtocol : 压缩格式
  • TJSONProtocol : JSON格式
  • TSimpleJSONProtocol : 提供JSON只写协议, 生成的文件很容易通过脚本语言解析
  • 等等

主要的方法有:

代码语言:javascript
复制
writeMessageBegin(name, type, seq)
writeMessageEnd()
writeStructBegin(name)
writeStructEnd()
writeFieldBegin(name, type, id)
writeFieldEnd()
writeFieldStop()
writeMapBegin(ktype, vtype, size)
writeMapEnd()
writeListBegin(etype, size)
writeListEnd()
writeSetBegin(etype, size)
writeSetEnd()
writeBool(bool)
writeByte(byte)
writeI16(i16)
writeI32(i32)
writeI64(i64)
writeDouble(double)
writeString(string)

读操作~

代码语言:javascript
复制
name, type, seq = readMessageBegin()
                  readMessageEnd()
name = readStructBegin()
       readStructEnd()
name, type, id = readFieldBegin()
                 readFieldEnd()
k, v, size = readMapBegin()
             readMapEnd()
etype, size = readListBegin()
              readListEnd()
etype, size = readSetBegin()
              readSetEnd()
bool = readBool()
byte = readByte()
i16 = readI16()
i32 = readI32()
i64 = readI64()
double = readDouble()
string = readString()

Processor

Processor封装了从输入数据流中读数据和向数据数据流中写数据的操作。读写数据流用Protocol对象表示。

Processor的结构体非常简单:

代码语言:javascript
复制
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.thrift;

import org.apache.thrift.protocol.TProtocol;

/**
 * A processor is a generic object which operates upon an input stream and
 * writes to some output stream.
 *
 */
public interface TProcessor {
  public boolean process(TProtocol in, TProtocol out)
    throws TException;
}

与服务相关的processor实现由编译器产生。

Processor主要工作流程如下: 从连接中读取数据(使用输入protocol),将处理授权给handler(由用户实现),最后将结果写到连接上(使用输出protocol)。

Server

Server将以上所有特性集成在一起,Server实现的几个步骤如下~

(1) 创建一个transport对象 (2) 为transport对象创建输入输出protocol (3) 基于输入输出protocol创建processor (4) 等待连接请求并将之交给processor处理

示例:

代码语言:javascript
复制
package com.xxx.tutorial.thrift.server;

import java.util.logging.Logger;

import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;

import com.xxx.tutorial.thrift.service.UserService;
import com.xxx.tutorial.thrift.service.impl.UserServiceImpl;

/**
 * @author wangmengjun
 *
 */
public class TSimpleServerExample {

	private static final Logger logger = Logger.getLogger(TSimpleServerExample.class.getName());

	private static final int SERVER_PORT = 9123;

	public static void main(String[] args) {

		try {
			
			/**
			 * 1. 创建Transport
			 */
			TServerSocket serverTransport = new TServerSocket(SERVER_PORT);
			TServer.Args tArgs = new TServer.Args(serverTransport);
			
			/**
			 * 2. 为Transport创建Protocol
			 */
			tArgs.protocolFactory(new TBinaryProtocol.Factory());
			// tArgs.protocolFactory(new TCompactProtocol.Factory());
			// tArgs.protocolFactory(new TJSONProtocol.Factory());
			
			/**
			 * 3. 为Protocol创建Processor
			 */
			TProcessor tprocessor = new UserService.Processor<UserService.Iface>(new UserServiceImpl());
			tArgs.processor(tprocessor);


			/**
			 * 4. 创建Server并启动
			 *
			 * org.apache.thrift.server.TSimpleServer - 简单的单线程服务模型,一般用于测试
			 */
			TServer server = new TSimpleServer(tArgs);
			logger.info("UserService TSimpleServer start ....");
			server.serve();
			

		} catch (Exception e) {
			logger.severe("Server start error!!!" + e.getLocalizedMessage());
			e.printStackTrace();
		}
	}
}

Thrift类型系统

Thrift类型系统包括预定义的基本类型(如bool , byte, double, string)、特殊类型(如binary)、用户自定义结构体(看上去像C 语言的结构体)、容器类型(如list,set,map)以及异常和服务定义~

基本类型(Base Type)

代码语言:javascript
复制
bool    :布尔类型(true or value),占一个字节
 
byte/i8 :有符号字节
 
i16     :  16位有符号整型
 
i32     :  32位有符号整型
 
i64     :  64位有符号整型
 
double  :64位浮点数
 
string  :未知编码或者二进制的字符串

注意, thrift不支持无符号整型,因为很多目标语言不存在无符号整型(如java)。

特殊类型(Special type)

代码语言:javascript
复制
binary   :未经过编码的字节流

Thrift基本类型、特殊类型和Java类型的对应关系如下表所示:

容器(container)

Thrift容器与类型密切相关,它与当前流行编程语言提供的容器类型相对应,Thrift提供了3种容器类型:

代码语言:javascript
复制
List<t1>   :一系列t1类型的元素组成的有序表,元素可以重复
 
Set<t1>    :一系列t1类型的元素组成的无序表,元素唯一

Map<t1,t2> :key/value对(key的类型是t1且key唯一,value类型是t2)

注意: 容器中的元素类型可以是除了service之外的任何合法thrift类型(包括结构体和异常)。

Thrift容器类型和Java类型的对应关系如下表所示:

结构(struct)

Thrift结构体在概念上同C语言结构体类型—-一种将相关属性聚集(封装)在一起的方式。在面向对象语言中,thrift结构体被转换成类,在Java语言中,这等价于JavaBean的概念~

如,

代码语言:javascript
复制
struct  User {  
  1:i32 userId,
  2:string name
}

异常(Exception)

异常在语法和功能上类似于结构体,只不过异常使用关键字exception而不是struct关键字声明。 但它在语义上不同于结构体—当定义一个RPC服务时,开发者可能需要声明一个远程方法抛出一个异常。

如,

代码语言:javascript
复制
exception MyException {
	1: string code;
	2: string message;
}

服务(Service)

一个服务包含一系列命名函数,每个函数包含一系列的参数以及一个返回类型。 在语法上,服务等价于定义一个接口或者纯虚抽象类~

格式如下,

代码语言:javascript
复制
service <name> {
  <returntype> <name> (<arguments>)
  [throws (<exceptions>)]
...
}

如,

代码语言:javascript
复制
service  UserService {
  string sayHello(1:string name);
}

其它语法参考

Typedefs

Thrift支持C/C++风格的typedef, 如

代码语言:javascript
复制
typedef i32 MyInteger

说明: a. 末尾没有逗号 b. struct可以使用typedef

代码语言:javascript
复制
typedef i32 MyInteger
 
struct  User {  
  1:MyInteger userId,
  2:string name
}

枚举Enums

可以像C/C++那样定义枚举类型,如:

代码语言:javascript
复制
enum Gender {
	MALE,
	FEMALE,
	UNKONWN
}

注释Comments

Thrfit支持shell注释风格,C/C++语言中单行或者多行注释风格

代码语言:javascript
复制
# This is a valid comment.
 
/*
 
* This is a multi-line comment.
 
* Just like in C.
 
*/
 
// C++/Java style single-line comments work just as well.

命名空间Namespace

Thrift中的命名空间同C++中的namespace和java中的package类似,它们均提供了一种组织(隔离)代码的方式。因为每种语言均有自己的命名空间定义方式(如python中有module),thrift允许开发者针对特定语言定义namespace:

代码语言:javascript
复制
namespace cpp com.example.project  // a
 
namespace java com.example.project // b

Includes

Thrift允许thrift文件包含,用户需要使用thrift文件名作为前缀访问被包含的对象,如:

代码语言:javascript
复制
include "user.thrift"

namespace java com.xxx.tutorial.thrift.service

service  UserService {

  string sayHello(1:string name),
  
  bool saveUser(1:user.User user)
}

说明: a. thrift文件名要用双引号包含,末尾没有逗号或者分号 b. 注意user前缀

常量Constants

Thrift允许用户定义常量,复杂的类型和结构体可使用JSON形式表示。

代码语言:javascript
复制
const i32 INT_CONST = 1234;    // a
 
const map<string,string> MAP_CONST = {"hello": "world", "goodnight": "moon"}

编写一个Thrift文件

有了上述Thrift IDL的语法参考之外,我们就可以来根据这些语法信息,编写thrift文件,并完成生成java代码,结合示例来体验一把~

基本类型和特殊类型

定义一个types.thrift文件,内容如下:

代码语言:javascript
复制
struct Types {

		1: bool boolValue;	
        2: i8   byteValue;
        3: i16  shortValue;
        4: i32  intValue;
        5: i64  longValue;
        6: double doubleValue;
        7: string stringValue;
        8: binary binaryValue;	

}

根据types.thrift生成的Types.java文件,类型相关的部分代码如下:

代码语言:javascript
复制
/**
 * Autogenerated by Thrift Compiler (0.10.0)
 *
 * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
 *  @generated
 */
@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2017-06-08")
public class Types implements org.apache.thrift.TBase<Types, Types._Fields>, java.io.Serializable, Cloneable, Comparable<Types> {
  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("Types");

  private static final org.apache.thrift.protocol.TField BOOL_VALUE_FIELD_DESC = new org.apache.thrift.protocol.TField("boolValue", org.apache.thrift.protocol.TType.BOOL, (short)1);
  private static final org.apache.thrift.protocol.TField BYTE_VALUE_FIELD_DESC = new org.apache.thrift.protocol.TField("byteValue", org.apache.thrift.protocol.TType.BYTE, (short)2);
  private static final org.apache.thrift.protocol.TField SHORT_VALUE_FIELD_DESC = new org.apache.thrift.protocol.TField("shortValue", org.apache.thrift.protocol.TType.I16, (short)3);
  private static final org.apache.thrift.protocol.TField INT_VALUE_FIELD_DESC = new org.apache.thrift.protocol.TField("intValue", org.apache.thrift.protocol.TType.I32, (short)4);
  private static final org.apache.thrift.protocol.TField LONG_VALUE_FIELD_DESC = new org.apache.thrift.protocol.TField("longValue", org.apache.thrift.protocol.TType.I64, (short)5);
  private static final org.apache.thrift.protocol.TField DOUBLE_VALUE_FIELD_DESC = new org.apache.thrift.protocol.TField("doubleValue", org.apache.thrift.protocol.TType.DOUBLE, (short)6);
  private static final org.apache.thrift.protocol.TField STRING_VALUE_FIELD_DESC = new org.apache.thrift.protocol.TField("stringValue", org.apache.thrift.protocol.TType.STRING, (short)7);
  private static final org.apache.thrift.protocol.TField BINARY_VALUE_FIELD_DESC = new org.apache.thrift.protocol.TField("binaryValue", org.apache.thrift.protocol.TType.STRING, (short)8);

  private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new TypesStandardSchemeFactory();
  private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new TypesTupleSchemeFactory();

  public boolean boolValue; // required
  public byte byteValue; // required
  public short shortValue; // required
  public int intValue; // required
  public long longValue; // required
  public double doubleValue; // required
  public java.lang.String stringValue; // required
  public java.nio.ByteBuffer binaryValue; // required

  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
    BOOL_VALUE((short)1, "boolValue"),
    BYTE_VALUE((short)2, "byteValue"),
    SHORT_VALUE((short)3, "shortValue"),
    INT_VALUE((short)4, "intValue"),
    LONG_VALUE((short)5, "longValue"),
    DOUBLE_VALUE((short)6, "doubleValue"),
    STRING_VALUE((short)7, "stringValue"),
    BINARY_VALUE((short)8, "binaryValue");

    private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();

    static {
      for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
        byName.put(field.getFieldName(), field);
      }
    }

    /**
     * Find the _Fields constant that matches fieldId, or null if its not found.
     */
    public static _Fields findByThriftId(int fieldId) {
      switch(fieldId) {
        case 1: // BOOL_VALUE
          return BOOL_VALUE;
        case 2: // BYTE_VALUE
          return BYTE_VALUE;
        case 3: // SHORT_VALUE
          return SHORT_VALUE;
        case 4: // INT_VALUE
          return INT_VALUE;
        case 5: // LONG_VALUE
          return LONG_VALUE;
        case 6: // DOUBLE_VALUE
          return DOUBLE_VALUE;
        case 7: // STRING_VALUE
          return STRING_VALUE;
        case 8: // BINARY_VALUE
          return BINARY_VALUE;
        default:
          return null;
      }
    }

    /**
     * Find the _Fields constant that matches fieldId, throwing an exception
     * if it is not found.
     */
    public static _Fields findByThriftIdOrThrow(int fieldId) {
      _Fields fields = findByThriftId(fieldId);
      if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
      return fields;
    }

    /**
     * Find the _Fields constant that matches name, or null if its not found.
     */
    public static _Fields findByName(java.lang.String name) {
      return byName.get(name);
    }

    private final short _thriftId;
    private final java.lang.String _fieldName;

    _Fields(short thriftId, java.lang.String fieldName) {
      _thriftId = thriftId;
      _fieldName = fieldName;
    }

    public short getThriftFieldId() {
      return _thriftId;
    }

    public java.lang.String getFieldName() {
      return _fieldName;
    }
  }

  // isset id assignments
  private static final int __BOOLVALUE_ISSET_ID = 0;
  private static final int __BYTEVALUE_ISSET_ID = 1;
  private static final int __SHORTVALUE_ISSET_ID = 2;
  private static final int __INTVALUE_ISSET_ID = 3;
  private static final int __LONGVALUE_ISSET_ID = 4;
  private static final int __DOUBLEVALUE_ISSET_ID = 5;
  private byte __isset_bitfield = 0;
  public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
  static {
    java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
    tmpMap.put(_Fields.BOOL_VALUE, new org.apache.thrift.meta_data.FieldMetaData("boolValue", org.apache.thrift.TFieldRequirementType.DEFAULT, 
        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.BOOL)));
    tmpMap.put(_Fields.BYTE_VALUE, new org.apache.thrift.meta_data.FieldMetaData("byteValue", org.apache.thrift.TFieldRequirementType.DEFAULT, 
        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.BYTE)));
    tmpMap.put(_Fields.SHORT_VALUE, new org.apache.thrift.meta_data.FieldMetaData("shortValue", org.apache.thrift.TFieldRequirementType.DEFAULT, 
        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I16)));
    tmpMap.put(_Fields.INT_VALUE, new org.apache.thrift.meta_data.FieldMetaData("intValue", org.apache.thrift.TFieldRequirementType.DEFAULT, 
        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32)));
    tmpMap.put(_Fields.LONG_VALUE, new org.apache.thrift.meta_data.FieldMetaData("longValue", org.apache.thrift.TFieldRequirementType.DEFAULT, 
        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64)));
    tmpMap.put(_Fields.DOUBLE_VALUE, new org.apache.thrift.meta_data.FieldMetaData("doubleValue", org.apache.thrift.TFieldRequirementType.DEFAULT, 
        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.DOUBLE)));
    tmpMap.put(_Fields.STRING_VALUE, new org.apache.thrift.meta_data.FieldMetaData("stringValue", org.apache.thrift.TFieldRequirementType.DEFAULT, 
        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
    tmpMap.put(_Fields.BINARY_VALUE, new org.apache.thrift.meta_data.FieldMetaData("binaryValue", org.apache.thrift.TFieldRequirementType.DEFAULT, 
        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING        , true)));
    metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(Types.class, metaDataMap);
  }

  public Types() {
  }

  public Types(
    boolean boolValue,
    byte byteValue,
    short shortValue,
    int intValue,
    long longValue,
    double doubleValue,
    java.lang.String stringValue,
    java.nio.ByteBuffer binaryValue)
{
    this();
    this.boolValue = boolValue;
    setBoolValueIsSet(true);
    this.byteValue = byteValue;
    setByteValueIsSet(true);
    this.shortValue = shortValue;
    setShortValueIsSet(true);
    this.intValue = intValue;
    setIntValueIsSet(true);
    this.longValue = longValue;
    setLongValueIsSet(true);
    this.doubleValue = doubleValue;
    setDoubleValueIsSet(true);
    this.stringValue = stringValue;
    this.binaryValue = org.apache.thrift.TBaseHelper.copyBinary(binaryValue);
  }

  /**
   * Performs a deep copy on <i>other</i>.
   */
  public Types(Types other) {
    __isset_bitfield = other.__isset_bitfield;
    this.boolValue = other.boolValue;
    this.byteValue = other.byteValue;
    this.shortValue = other.shortValue;
    this.intValue = other.intValue;
    this.longValue = other.longValue;
    this.doubleValue = other.doubleValue;
    if (other.isSetStringValue()) {
      this.stringValue = other.stringValue;
    }
    if (other.isSetBinaryValue()) {
      this.binaryValue = org.apache.thrift.TBaseHelper.copyBinary(other.binaryValue);
    }
  }

  public Types deepCopy() {
    return new Types(this);
  }

  @Override
  public void clear() {
    setBoolValueIsSet(false);
    this.boolValue = false;
    setByteValueIsSet(false);
    this.byteValue = 0;
    setShortValueIsSet(false);
    this.shortValue = 0;
    setIntValueIsSet(false);
    this.intValue = 0;
    setLongValueIsSet(false);
    this.longValue = 0;
    setDoubleValueIsSet(false);
    this.doubleValue = 0.0;
    this.stringValue = null;
    this.binaryValue = null;
  }

  public boolean isBoolValue() {
    return this.boolValue;
  }

  public Types setBoolValue(boolean boolValue) {
    this.boolValue = boolValue;
    setBoolValueIsSet(true);
    return this;
  }

 ... ...

}

可以看出来,thrift文件中定义的类型,转换成java代码的类型,和下面表格展示的是一致的~

枚举类

定义一个枚举 gender.thrift

代码语言:javascript
复制
enum Gender {
	MALE,
	FEMALE,
	UNKONWN
}

根据gender.thrift生成的java代码如下:

代码语言:javascript
复制
/**
 * Autogenerated by Thrift Compiler (0.10.0)
 *
 * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
 *  @generated
 */

import java.util.Map;
import java.util.HashMap;
import org.apache.thrift.TEnum;

public enum Gender implements org.apache.thrift.TEnum {
  MALE(0),
  FEMALE(1),
  UNKONWN(2);

  private final int value;

  private Gender(int value) {
    this.value = value;
  }

  /**
   * Get the integer value of this enum value, as defined in the Thrift IDL.
   */
  public int getValue() {
    return value;
  }

  /**
   * Find a the enum type by its integer value, as defined in the Thrift IDL.
   * @return null if the value is not found.
   */
  public static Gender findByValue(int value) { 
    switch (value) {
      case 0:
        return MALE;
      case 1:
        return FEMALE;
      case 2:
        return UNKONWN;
      default:
        return null;
    }
  }
}

异常exception

创建一个exception.thrift文件,并写入如下几个属性~

代码语言:javascript
复制
exception MyException {
	1: string code;
	2: string message;
}

根据exception.thrift生成java代码

代码语言:javascript
复制
/**
 * Autogenerated by Thrift Compiler (0.10.0)
 *
 * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
 *  @generated
 */
@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2017-06-08")
public class MyException extends org.apache.thrift.TException implements org.apache.thrift.TBase<MyException, MyException._Fields>, java.io.Serializable, Cloneable, Comparable<MyException> {
  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("MyException");

  private static final org.apache.thrift.protocol.TField CODE_FIELD_DESC = new org.apache.thrift.protocol.TField("code", org.apache.thrift.protocol.TType.STRING, (short)1);
  private static final org.apache.thrift.protocol.TField MESSAGE_FIELD_DESC = new org.apache.thrift.protocol.TField("message", org.apache.thrift.protocol.TType.STRING, (short)2);

  private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new MyExceptionStandardSchemeFactory();
  private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new MyExceptionTupleSchemeFactory();

  public java.lang.String code; // required
  public java.lang.String message; // required

  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
    CODE((short)1, "code"),
    MESSAGE((short)2, "message");

    private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();

    static {
      for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
        byName.put(field.getFieldName(), field);
      }
    }

    /**
     * Find the _Fields constant that matches fieldId, or null if its not found.
     */
    public static _Fields findByThriftId(int fieldId) {
      switch(fieldId) {
        case 1: // CODE
          return CODE;
        case 2: // MESSAGE
          return MESSAGE;
        default:
          return null;
      }
    }

    /**
     * Find the _Fields constant that matches fieldId, throwing an exception
     * if it is not found.
     */
    public static _Fields findByThriftIdOrThrow(int fieldId) {
      _Fields fields = findByThriftId(fieldId);
      if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
      return fields;
    }

    /**
     * Find the _Fields constant that matches name, or null if its not found.
     */
    public static _Fields findByName(java.lang.String name) {
      return byName.get(name);
    }

    private final short _thriftId;
    private final java.lang.String _fieldName;

    _Fields(short thriftId, java.lang.String fieldName) {
      _thriftId = thriftId;
      _fieldName = fieldName;
    }

    public short getThriftFieldId() {
      return _thriftId;
    }

    public java.lang.String getFieldName() {
      return _fieldName;
    }
  }

  // isset id assignments
  public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
  static {
    java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
    tmpMap.put(_Fields.CODE, new org.apache.thrift.meta_data.FieldMetaData("code", org.apache.thrift.TFieldRequirementType.DEFAULT, 
        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
    tmpMap.put(_Fields.MESSAGE, new org.apache.thrift.meta_data.FieldMetaData("message", org.apache.thrift.TFieldRequirementType.DEFAULT, 
        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
    metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(MyException.class, metaDataMap);
  }

  public MyException() {
  }

  public MyException(
    java.lang.String code,
    java.lang.String message)
{
    this();
    this.code = code;
    this.message = message;
  }

  /**
   * Performs a deep copy on <i>other</i>.
   */
  public MyException(MyException other) {
    if (other.isSetCode()) {
      this.code = other.code;
    }
    if (other.isSetMessage()) {
      this.message = other.message;
    }
  }

  public MyException deepCopy() {
    return new MyException(this);
  }

  @Override
  public void clear() {
    this.code = null;
    this.message = null;
  }

  public java.lang.String getCode() {
    return this.code;
  }

  public MyException setCode(java.lang.String code) {
    this.code = code;
    return this;
  }

  public void unsetCode() {
    this.code = null;
  }

  /** Returns true if field code is set (has been assigned a value) and false otherwise */
  public boolean isSetCode() {
    return this.code != null;
  }

  public void setCodeIsSet(boolean value) {
    if (!value) {
      this.code = null;
    }
  }

  public java.lang.String getMessage() {
    return this.message;
  }

  public MyException setMessage(java.lang.String message) {
    this.message = message;
    return this;
  }

  public void unsetMessage() {
    this.message = null;
  }

  /** Returns true if field message is set (has been assigned a value) and false otherwise */
  public boolean isSetMessage() {
    return this.message != null;
  }

  public void setMessageIsSet(boolean value) {
    if (!value) {
      this.message = null;
    }
  }

  public void setFieldValue(_Fields field, java.lang.Object value) {
    switch (field) {
    case CODE:
      if (value == null) {
        unsetCode();
      } else {
        setCode((java.lang.String)value);
      }
      break;

    case MESSAGE:
      if (value == null) {
        unsetMessage();
      } else {
        setMessage((java.lang.String)value);
      }
      break;

    }
  }

  public java.lang.Object getFieldValue(_Fields field) {
    switch (field) {
    case CODE:
      return getCode();

    case MESSAGE:
      return getMessage();

    }
    throw new java.lang.IllegalStateException();
  }

  /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
  public boolean isSet(_Fields field) {
    if (field == null) {
      throw new java.lang.IllegalArgumentException();
    }

    switch (field) {
    case CODE:
      return isSetCode();
    case MESSAGE:
      return isSetMessage();
    }
    throw new java.lang.IllegalStateException();
  }

  @Override
  public boolean equals(java.lang.Object that) {
    if (that == null)
      return false;
    if (that instanceof MyException)
      return this.equals((MyException)that);
    return false;
  }

  public boolean equals(MyException that) {
    if (that == null)
      return false;
    if (this == that)
      return true;

    boolean this_present_code = true && this.isSetCode();
    boolean that_present_code = true && that.isSetCode();
    if (this_present_code || that_present_code) {
      if (!(this_present_code && that_present_code))
        return false;
      if (!this.code.equals(that.code))
        return false;
    }

    boolean this_present_message = true && this.isSetMessage();
    boolean that_present_message = true && that.isSetMessage();
    if (this_present_message || that_present_message) {
      if (!(this_present_message && that_present_message))
        return false;
      if (!this.message.equals(that.message))
        return false;
    }

    return true;
  }

  @Override
  public int hashCode() {
    int hashCode = 1;

    hashCode = hashCode * 8191 + ((isSetCode()) ? 131071 : 524287);
    if (isSetCode())
      hashCode = hashCode * 8191 + code.hashCode();

    hashCode = hashCode * 8191 + ((isSetMessage()) ? 131071 : 524287);
    if (isSetMessage())
      hashCode = hashCode * 8191 + message.hashCode();

    return hashCode;
  }

  @Override
  public int compareTo(MyException other) {
    if (!getClass().equals(other.getClass())) {
      return getClass().getName().compareTo(other.getClass().getName());
    }

    int lastComparison = 0;

    lastComparison = java.lang.Boolean.valueOf(isSetCode()).compareTo(other.isSetCode());
    if (lastComparison != 0) {
      return lastComparison;
    }
    if (isSetCode()) {
      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.code, other.code);
      if (lastComparison != 0) {
        return lastComparison;
      }
    }
    lastComparison = java.lang.Boolean.valueOf(isSetMessage()).compareTo(other.isSetMessage());
    if (lastComparison != 0) {
      return lastComparison;
    }
    if (isSetMessage()) {
      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.message, other.message);
      if (lastComparison != 0) {
        return lastComparison;
      }
    }
    return 0;
  }

  public _Fields fieldForId(int fieldId) {
    return _Fields.findByThriftId(fieldId);
  }

  public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
    scheme(iprot).read(iprot, this);
  }

  public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
    scheme(oprot).write(oprot, this);
  }

  @Override
  public java.lang.String toString() {
    java.lang.StringBuilder sb = new java.lang.StringBuilder("MyException(");
    boolean first = true;

    sb.append("code:");
    if (this.code == null) {
      sb.append("null");
    } else {
      sb.append(this.code);
    }
    first = false;
    if (!first) sb.append(", ");
    sb.append("message:");
    if (this.message == null) {
      sb.append("null");
    } else {
      sb.append(this.message);
    }
    first = false;
    sb.append(")");
    return sb.toString();
  }

  public void validate() throws org.apache.thrift.TException {
    // check for required fields
    // check for sub-struct validity
  }

  private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
    try {
      write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
    } catch (org.apache.thrift.TException te) {
      throw new java.io.IOException(te);
    }
  }

  private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException {
    try {
      read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
    } catch (org.apache.thrift.TException te) {
      throw new java.io.IOException(te);
    }
  }

  private static class MyExceptionStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
    public MyExceptionStandardScheme getScheme() {
      return new MyExceptionStandardScheme();
    }
  }

  private static class MyExceptionStandardScheme extends org.apache.thrift.scheme.StandardScheme<MyException> {

    public void read(org.apache.thrift.protocol.TProtocol iprot, MyException struct) throws org.apache.thrift.TException {
      org.apache.thrift.protocol.TField schemeField;
      iprot.readStructBegin();
      while (true)
      {
        schemeField = iprot.readFieldBegin();
        if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
          break;
        }
        switch (schemeField.id) {
          case 1: // CODE
            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
              struct.code = iprot.readString();
              struct.setCodeIsSet(true);
            } else { 
              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
            }
            break;
          case 2: // MESSAGE
            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
              struct.message = iprot.readString();
              struct.setMessageIsSet(true);
            } else { 
              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
            }
            break;
          default:
            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
        }
        iprot.readFieldEnd();
      }
      iprot.readStructEnd();

      // check for required fields of primitive type, which can't be checked in the validate method
      struct.validate();
    }

    public void write(org.apache.thrift.protocol.TProtocol oprot, MyException struct) throws org.apache.thrift.TException {
      struct.validate();

      oprot.writeStructBegin(STRUCT_DESC);
      if (struct.code != null) {
        oprot.writeFieldBegin(CODE_FIELD_DESC);
        oprot.writeString(struct.code);
        oprot.writeFieldEnd();
      }
      if (struct.message != null) {
        oprot.writeFieldBegin(MESSAGE_FIELD_DESC);
        oprot.writeString(struct.message);
        oprot.writeFieldEnd();
      }
      oprot.writeFieldStop();
      oprot.writeStructEnd();
    }

  }

  private static class MyExceptionTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
    public MyExceptionTupleScheme getScheme() {
      return new MyExceptionTupleScheme();
    }
  }

  private static class MyExceptionTupleScheme extends org.apache.thrift.scheme.TupleScheme<MyException> {

    @Override
    public void write(org.apache.thrift.protocol.TProtocol prot, MyException struct) throws org.apache.thrift.TException {
      org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
      java.util.BitSet optionals = new java.util.BitSet();
      if (struct.isSetCode()) {
        optionals.set(0);
      }
      if (struct.isSetMessage()) {
        optionals.set(1);
      }
      oprot.writeBitSet(optionals, 2);
      if (struct.isSetCode()) {
        oprot.writeString(struct.code);
      }
      if (struct.isSetMessage()) {
        oprot.writeString(struct.message);
      }
    }

    @Override
    public void read(org.apache.thrift.protocol.TProtocol prot, MyException struct) throws org.apache.thrift.TException {
      org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
      java.util.BitSet incoming = iprot.readBitSet(2);
      if (incoming.get(0)) {
        struct.code = iprot.readString();
        struct.setCodeIsSet(true);
      }
      if (incoming.get(1)) {
        struct.message = iprot.readString();
        struct.setMessageIsSet(true);
      }
    }
  }

  private static <S extends org.apache.thrift.scheme.IScheme> S scheme(org.apache.thrift.protocol.TProtocol proto) {
    return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme();
  }
}

容器

编写user.thrift,用于定义一个User类, 会在集合类中使用~

代码语言:javascript
复制
namespace java com.xxx.tutorial.thrift.entity  

/**
 * 用户类
 */
struct  User {  
  1:i32 userId,
  2:string name
}  

创建containerTypes.thrift,用于使用容器类型,包括list、map和set~

代码语言:javascript
复制
include "user.thrift"

namespace java com.xxx.tutorial.rpc.entity

struct ContainerTypes {

		1: list<string> stringValueList;	
		2: set<string> stringValueSet;
		3: map<string,string> stringValueMap;
		4: list<user.User> userList;
		
}

根据thrift文件生成java代码~

代码语言:javascript
复制
/**
 * Autogenerated by Thrift Compiler (0.10.0)
 *
 * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
 *  @generated
 */
package com.xxx.tutorial.rpc.entity;

@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2017-06-08")
public class ContainerTypes implements org.apache.thrift.TBase<ContainerTypes, ContainerTypes._Fields>, java.io.Serializable, Cloneable, Comparable<ContainerTypes> {
  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("ContainerTypes");

  private static final org.apache.thrift.protocol.TField STRING_VALUE_LIST_FIELD_DESC = new org.apache.thrift.protocol.TField("stringValueList", org.apache.thrift.protocol.TType.LIST, (short)1);
  private static final org.apache.thrift.protocol.TField STRING_VALUE_SET_FIELD_DESC = new org.apache.thrift.protocol.TField("stringValueSet", org.apache.thrift.protocol.TType.SET, (short)2);
  private static final org.apache.thrift.protocol.TField STRING_VALUE_MAP_FIELD_DESC = new org.apache.thrift.protocol.TField("stringValueMap", org.apache.thrift.protocol.TType.MAP, (short)3);
  private static final org.apache.thrift.protocol.TField USER_LIST_FIELD_DESC = new org.apache.thrift.protocol.TField("userList", org.apache.thrift.protocol.TType.LIST, (short)4);

  private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new ContainerTypesStandardSchemeFactory();
  private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new ContainerTypesTupleSchemeFactory();

  public java.util.List<java.lang.String> stringValueList; // required
  public java.util.Set<java.lang.String> stringValueSet; // required
  public java.util.Map<java.lang.String,java.lang.String> stringValueMap; // required
  public java.util.List<com.xxx.tutorial.thrift.entity.User> userList; // required

  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
    STRING_VALUE_LIST((short)1, "stringValueList"),
    STRING_VALUE_SET((short)2, "stringValueSet"),
    STRING_VALUE_MAP((short)3, "stringValueMap"),
    USER_LIST((short)4, "userList");

    private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();

    static {
      for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
        byName.put(field.getFieldName(), field);
      }
    }

    /**
     * Find the _Fields constant that matches fieldId, or null if its not found.
     */
    public static _Fields findByThriftId(int fieldId) {
      switch(fieldId) {
        case 1: // STRING_VALUE_LIST
          return STRING_VALUE_LIST;
        case 2: // STRING_VALUE_SET
          return STRING_VALUE_SET;
        case 3: // STRING_VALUE_MAP
          return STRING_VALUE_MAP;
        case 4: // USER_LIST
          return USER_LIST;
        default:
          return null;
      }
    }

... ... 

}

从上述生成的代码可以看出,thrift文件中定义的容器类型转换成Java类型之后,与下图展示的内容一致~

服务Service

编写一个exception.thrift, 用于自定义异常类~

代码语言:javascript
复制

namespace java com.xxx.tutorial.rpc.exception

exception UserNotFoundException {
	1: string code;
	2: string message;
}

编写userService.thrift, 用于服务接口定义~

代码语言:javascript
复制
include "user.thrift"
include "exception.thrift"

namespace java com.xxx.tutorial.thrift.service  

/**
 * 用户服务
 */
service  UserService {   

  /**保存用户*/ 
  bool save(1:user.User user),
  
  /**根据name获取用户列表*/ 
  list<user.User> findUsersByName(1:string name),
  
  /**删除用户*/ 
  void deleteByUserId(1:i32 userId) throws (1: exception.UserNotFoundException e)
}  

生成的UserService代码

代码语言:javascript
复制
package com.xxx.tutorial.thrift.service;

@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2017-06-08")
public class UserService {

  /**
   * 用户服务
   */
  public interface Iface {

    /**
     * 保存用户
     * 
     * @param user
     */
    public boolean save(com.xxx.tutorial.thrift.entity.User user) throws org.apache.thrift.TException;

    /**
     * 根据name获取用户列表
     * 
     * @param name
     */
    public java.util.List<com.xxx.tutorial.thrift.entity.User> findUsersByName(java.lang.String name) throws org.apache.thrift.TException;

    /**
     * 删除用户
     * 
     * @param userId
     */
    public void deleteByUserId(int userId) throws com.xxx.tutorial.rpc.exception.UserNotFoundException, org.apache.thrift.TException;

  }

  public interface AsyncIface {

    public void save(com.xxx.tutorial.thrift.entity.User user, org.apache.thrift.async.AsyncMethodCallback<java.lang.Boolean> resultHandler) throws org.apache.thrift.TException;

    public void findUsersByName(java.lang.String name, org.apache.thrift.async.AsyncMethodCallback<java.util.List<com.xxx.tutorial.thrift.entity.User>> resultHandler) throws org.apache.thrift.TException;

    public void deleteByUserId(int userId, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;

  }

  public static class Client extends org.apache.thrift.TServiceClient implements Iface {
    public static class Factory implements org.apache.thrift.TServiceClientFactory<Client> {
      public Factory() {}
      public Client getClient(org.apache.thrift.protocol.TProtocol prot) {
        return new Client(prot);
      }
      public Client getClient(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {
        return new Client(iprot, oprot);
      }
    }

    public Client(org.apache.thrift.protocol.TProtocol prot)
{
      super(prot, prot);
    }

    public Client(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {
      super(iprot, oprot);
    }

    public boolean save(com.xxx.tutorial.thrift.entity.User user) throws org.apache.thrift.TException
{
      send_save(user);
      return recv_save();
    }

    public void send_save(com.xxx.tutorial.thrift.entity.User user) throws org.apache.thrift.TException
{
      save_args args = new save_args();
      args.setUser(user);
      sendBase("save", args);
    }

    public boolean recv_save() throws org.apache.thrift.TException
{
      save_result result = new save_result();
      receiveBase(result, "save");
      if (result.isSetSuccess()) {
        return result.success;
      }
      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "save failed: unknown result");
    }

    public java.util.List<com.xxx.tutorial.thrift.entity.User> findUsersByName(java.lang.String name) throws org.apache.thrift.TException
    {
      send_findUsersByName(name);
      return recv_findUsersByName();
    }

    public void send_findUsersByName(java.lang.String name) throws org.apache.thrift.TException
{
      findUsersByName_args args = new findUsersByName_args();
      args.setName(name);
      sendBase("findUsersByName", args);
    }

    public java.util.List<com.xxx.tutorial.thrift.entity.User> recv_findUsersByName() throws org.apache.thrift.TException
    {
      findUsersByName_result result = new findUsersByName_result();
      receiveBase(result, "findUsersByName");
      if (result.isSetSuccess()) {
        return result.success;
      }
      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "findUsersByName failed: unknown result");
    }

    public void deleteByUserId(int userId) throws com.xxx.tutorial.rpc.exception.UserNotFoundException, org.apache.thrift.TException
{
      send_deleteByUserId(userId);
      recv_deleteByUserId();
    }

    public void send_deleteByUserId(int userId) throws org.apache.thrift.TException
{
      deleteByUserId_args args = new deleteByUserId_args();
      args.setUserId(userId);
      sendBase("deleteByUserId", args);
    }

    public void recv_deleteByUserId() throws com.xxx.tutorial.rpc.exception.UserNotFoundException, org.apache.thrift.TException
{
      deleteByUserId_result result = new deleteByUserId_result();
      receiveBase(result, "deleteByUserId");
      if (result.e != null) {
        throw result.e;
      }
      return;
    }

  }

... ... 

}

示例

说明

在这个示例中,我们主要在用户接口中定义三个接口:保存用户,根据name获取用户列表以及删除用户,如:

代码语言:javascript
复制
 /**
     * 保存用户
     * 
     * @param user
     */
    public boolean save(com.xxx.tutorial.thrift.entity.User user) throws org.apache.thrift.TException;

    /**
     * 根据name获取用户列表
     * 
     * @param name
     */
    public java.util.List<com.xxx.tutorial.thrift.entity.User> findUsersByName(java.lang.String name) throws org.apache.thrift.TException;

    /**
     * 删除用户
     * 
     * @param userId
     */
    public void deleteByUserId(int userId) throws com.xxx.tutorial.thrift.exception.UserNotFoundException, org.apache.thrift.TException;

然后使用多种Server创建方法,Thrift支持的Serer有多种,如TSimpleServer、TThreadPoolServer等~

产生代码

根据thrift文件生成Java代码,这里就不再描述,请参考以前的博文【一步步完成thrift rpc示例

接口代码

将生成的Java代码放入thrift-demo-interface模块~ 如,

实现代码

在thrift-demo-service模块增加UserService的实现类~

UserServiceImpl.java的内容如下:

代码语言:javascript
复制
/**
 * 
 */
package com.xxx.tutorial.thrift.service.impl;

import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;

import org.apache.thrift.TException;

import com.xxx.tutorial.thrift.entity.User;
import com.xxx.tutorial.thrift.exception.UserNotFoundException;
import com.xxx.tutorial.thrift.service.UserService;

/**
 * @author wangmengjun
 *
 */
public class UserServiceImpl implements UserService.Iface {

  private static final Logger logger = Logger.getLogger(UserServiceImpl.class.getName());

  public boolean save(User user) throws TException {
    logger.info("方法save的参数user的内容==>" + user.toString());
    return true;
  }

  public List<User> findUsersByName(String name) throws TException {
    logger.info("方法findUsersByName的参数name的内容==>" + name);
    return Arrays.asList(new User(1, "Wang"), new User(2, "Mengjun"));
  }

  public void deleteByUserId(int userId) throws UserNotFoundException, TException {
    /**
     * 直接模拟抛出异常,用于测试
     */
    logger.info("方法deleteByUserId的参数userId的内容==>" + userId);
    throw new UserNotFoundException("1001", String.format("userId=%d的用户不存在", userId));
  }
}

有了实现之后,就可以编写Server端的代码和Client端调用的代码~

TSimpleServer(阻塞IO)

在thrift-demo-server模块编写服务端代码~

四个步骤创建Server,如:

代码语言:javascript
复制
package com.xxx.tutorial.thrift.server;

import java.util.logging.Logger;

import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;

import com.xxx.tutorial.thrift.service.UserService;
import com.xxx.tutorial.thrift.service.impl.UserServiceImpl;

/**
 * @author wangmengjun
 *
 */
public class TSimpleServerExample {

  private static final Logger logger = Logger.getLogger(TSimpleServerExample.class.getName());

  private static final int SERVER_PORT = 9123;

  public static void main(String[] args) {

    try {
      
      /**
       * 1. 创建Transport
       */
      TServerSocket serverTransport = new TServerSocket(SERVER_PORT);
      TServer.Args tArgs = new TServer.Args(serverTransport);
      
      /**
       * 2. 为Transport创建Protocol
       */
      tArgs.protocolFactory(new TBinaryProtocol.Factory());
      // tArgs.protocolFactory(new TCompactProtocol.Factory());
      // tArgs.protocolFactory(new TJSONProtocol.Factory());
      
      /**
       * 3. 为Protocol创建Processor
       */
      TProcessor tprocessor = new UserService.Processor<UserService.Iface>(new UserServiceImpl());
      tArgs.processor(tprocessor);


      /**
       * 4. 创建Server并启动
       * 
       * org.apache.thrift.server.TSimpleServer - 简单的单线程服务模型,一般用于测试
       */
      TServer server = new TSimpleServer(tArgs);
      logger.info("UserService TSimpleServer start ....");
      server.serve();
      

    } catch (Exception e) {
      logger.severe("Server start error!!!" + e.getLocalizedMessage());
      e.printStackTrace();
    }
  }
}

启动Server,

代码语言:javascript
复制
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
六月 08, 2017 7:03:46 下午 com.xxx.tutorial.thrift.server.TSimpleServerExample main
信息: UserService TSimpleServer start ....

在thrift-demo-client模块编写客户端代码~

如:

代码语言:javascript
复制
package com.xxx.tutorial.thrift.client;

import java.util.List;
import java.util.logging.Logger;

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 org.apache.thrift.transport.TTransportException;

import com.xxx.tutorial.thrift.entity.User;
import com.xxx.tutorial.thrift.exception.UserNotFoundException;
import com.xxx.tutorial.thrift.service.UserService;

public class UserClient {

  private static final Logger logger = Logger.getLogger(UserClient.class.getName());

  public static void main(String[] args) {
    
    try {

      TTransport transport = new TSocket("127.0.0.1", 9123);
      TProtocol protocol = new TBinaryProtocol(transport);

      UserService.Client client = new UserService.Client(protocol);
      transport.open();

      /**
       * 查询User列表
       */
      List<User> users = client.findUsersByName("wang");
      logger.info("client.findUsersByName()方法結果 == >" + users);

      /**
       * 保存User
       */
      boolean isUserSaved = client.save(new User(101, "WMJ"));
      logger.info("user saved result == > " + isUserSaved);

      /**
       * 删除用户
       */
      client.deleteByUserId(1002);

      transport.close();

    } catch (TTransportException e) {
      logger.severe("TTransportException==>" + e.getLocalizedMessage());
    } catch (UserNotFoundException e) {
      logger.severe("UserNotFoundException==>" + e.getLocalizedMessage());
    } catch (TException e) {
      logger.severe("TException==>" + e.getLocalizedMessage());
    }
  }
}

三个方法的结果都有了~

代码语言:javascript
复制
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Received 1
六月 08, 2017 7:06:21 下午 com.xxx.tutorial.thrift.client.UserClient main
信息: client.findUsersByName()方法結果 == >[User(userId:1, name:Wang), User(userId:2, name:Mengjun)]
Received 2
六月 08, 2017 7:06:21 下午 com.xxx.tutorial.thrift.client.UserClient main
信息: user saved result == > true
Received 3
六月 08, 2017 7:06:21 下午 com.xxx.tutorial.thrift.client.UserClient main
严重: UserNotFoundException==>userId=1002的用户不存在

就这样,阻塞IO的示例就完成了~

TThreadPoolServer(多线程阻塞IO)

服务端代码示例:

代码语言:javascript
复制
package com.xxx.tutorial.thrift.server;

import java.util.logging.Logger;

import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;

import com.xxx.tutorial.thrift.service.UserService;
import com.xxx.tutorial.thrift.service.impl.UserServiceImpl;

/**
 * 
 * @author wangmengjun
 *
 */
public class TThreadPoolServerExample {

  private static final Logger logger = Logger.getLogger(TThreadPoolServerExample.class.getName());

  private static final int SERVER_PORT = 9125;

  public static void main(String[] args) {

    try {
      
      /**
       * 1. 创建Transport
       */
      TServerSocket serverTransport = new TServerSocket(SERVER_PORT);
      TThreadPoolServer.Args tArgs = new TThreadPoolServer.Args(serverTransport);
      
      /**
       * 2. 为Transport创建Protocol
       */
      tArgs.protocolFactory(new TBinaryProtocol.Factory());
      // tArgs.protocolFactory(new TCompactProtocol.Factory());
      // tArgs.protocolFactory(new TJSONProtocol.Factory());
      
      /**
       * 3. 为Protocol创建Processor
       */
      TProcessor tprocessor = new UserService.Processor<UserService.Iface>(new UserServiceImpl());
      tArgs.processor(tprocessor);


      /**
       * 4. 创建Server并启动
       * 
       * org.apache.thrift.server.TThreadPoolServer - 简单的单线程服务模型,一般用于测试
       */
      TServer server = new TThreadPoolServer(tArgs);
      logger.info("UserService TSimpleServer start ....");
      server.serve();
      

    } catch (Exception e) {
      logger.severe("Server start error!!!" + e.getLocalizedMessage());
      e.printStackTrace();
    }
  }
}

同样客户端的代码还可以是:

代码语言:javascript
复制
package com.xxx.tutorial.thrift.client;

import java.util.List;
import java.util.logging.Logger;

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 org.apache.thrift.transport.TTransportException;

import com.xxx.tutorial.thrift.entity.User;
import com.xxx.tutorial.thrift.exception.UserNotFoundException;
import com.xxx.tutorial.thrift.service.UserService;

public class UserClient {

	private static final Logger logger = Logger.getLogger(UserClient.class.getName());

	public static void main(String[] args) {
		
		try {

			TTransport transport = new TSocket("127.0.0.1", 9123);
			TProtocol protocol = new TBinaryProtocol(transport);

			UserService.Client client = new UserService.Client(protocol);
			transport.open();

			/**
			 * 查询User列表
			 */
			List<User> users = client.findUsersByName("wang");
			logger.info("client.findUsersByName()方法結果 == >" + users);

			/**
			 * 保存User
			 */
			boolean isUserSaved = client.save(new User(101, "WMJ"));
			logger.info("user saved result == > " + isUserSaved);

			/**
			 * 删除用户
			 */
			client.deleteByUserId(1002);

			transport.close();

		} catch (TTransportException e) {
			logger.severe("TTransportException==>" + e.getLocalizedMessage());
		} catch (UserNotFoundException e) {
			logger.severe("UserNotFoundException==>" + e.getLocalizedMessage());
		} catch (TException e) {
			logger.severe("TException==>" + e.getLocalizedMessage());
		}
	}
}

同样调用成功

服务端也打印了方法调用的信息:

代码语言:javascript
复制
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
六月 08, 2017 7:43:35 下午 com.xxx.tutorial.thrift.server.TThreadPoolServerExample main
信息: UserService TSimpleServer start ....
六月 08, 2017 7:43:39 下午 com.xxx.tutorial.thrift.service.impl.UserServiceImpl findUsersByName
信息: 方法findUsersByName的参数name的内容==>wang
六月 08, 2017 7:43:39 下午 com.xxx.tutorial.thrift.service.impl.UserServiceImpl save
信息: 方法save的参数user的内容==>User(userId:101, name:WMJ)
六月 08, 2017 7:43:39 下午 com.xxx.tutorial.thrift.service.impl.UserServiceImpl deleteByUserId
信息: 方法deleteByUserId的参数userId的内容==>1002

THsHaServer(多线程 NIO)

THsHaServer的描述如下:

代码语言:javascript
复制
/**
 * An extension of the TNonblockingServer to a Half-Sync/Half-Async server.
 * Like TNonblockingServer, it relies on the use of TFramedTransport.
 */
public class THsHaServer extends TNonblockingServer {

... ...

}

THsHaServer使用了Java NIO channel~ 在这种Server类型下,一定要使用TFrameTransport~

服务端代码示例如下:

代码语言:javascript
复制
package com.xxx.tutorial.thrift.server;

import java.util.logging.Logger;

import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.THsHaServer;
import org.apache.thrift.server.TServer;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TNonblockingServerSocket;

import com.xxx.tutorial.thrift.service.UserService;
import com.xxx.tutorial.thrift.service.impl.UserServiceImpl;

/**
 * @author wangmengjun
 *
 */
public class THsHaServerExample {

	private static final Logger logger = Logger.getLogger(THsHaServerExample.class.getName());

	private static final int SERVER_PORT = 9123;

	public static void main(String[] args) {

		try {
			
			/**
			 * 1. 创建Transport
			 */
			//TServerSocket serverTransport = new TServerSocket(SERVER_PORT);
			TNonblockingServerSocket serverTransport = new TNonblockingServerSocket(SERVER_PORT);
			THsHaServer.Args tArgs = new THsHaServer.Args(serverTransport);
			
			/**
			 * 2. 为Transport创建Protocol
			 */
			tArgs.transportFactory(new TFramedTransport.Factory());
			tArgs.protocolFactory(new TBinaryProtocol.Factory());
			// tArgs.protocolFactory(new TCompactProtocol.Factory());
			// tArgs.protocolFactory(new TJSONProtocol.Factory());
			
			/**
			 * 3. 为Protocol创建Processor
			 */
			TProcessor tprocessor = new UserService.Processor<UserService.Iface>(new UserServiceImpl());
			tArgs.processor(tprocessor);


			/**
			 * 4. 创建Server并启动
			 * 
			 * org.apache.thrift.server.TSimpleServer - 简单的单线程服务模型,一般用于测试
			 */
			//TServer server = new TSimpleServer(tArgs);
			//半同步半异步的服务模型
			TServer server = new THsHaServer(tArgs);
			logger.info("UserService TSimpleServer start ....");
			server.serve();
			

		} catch (Exception e) {
			logger.severe("Server start error!!!" + e.getLocalizedMessage());
			e.printStackTrace();
		}
	}
}

客户端代码如下:

代码语言:javascript
复制
package com.xxx.tutorial.thrift.client;

import java.util.List;
import java.util.logging.Logger;

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;

import com.xxx.tutorial.thrift.entity.User;
import com.xxx.tutorial.thrift.exception.UserNotFoundException;
import com.xxx.tutorial.thrift.service.UserService;

public class UserClient2 {

	private static final Logger logger = Logger.getLogger(UserClient.class.getName());

	public static void main(String[] args) {

		try {

			TTransport transport = new TFramedTransport(new TSocket("127.0.0.1", 9123, 3000));
			TProtocol protocol = new TBinaryProtocol(transport);

			UserService.Client client = new UserService.Client(protocol);
			transport.open();

			/**
			 * 查询User列表
			 */
			List<User> users = client.findUsersByName("wang");
			logger.info("client.findUsersByName()方法結果 == >" + users);

			/**
			 * 保存User
			 */
			boolean isUserSaved = client.save(new User(101, "WMJ"));
			logger.info("user saved result == > " + isUserSaved);

			/**
			 * 删除用户
			 */
			client.deleteByUserId(1002);

			transport.close();

		} catch (TTransportException e) {
			logger.severe("TTransportException==>" + e.getLocalizedMessage());
		} catch (UserNotFoundException e) {
			logger.severe("UserNotFoundException==>" + e.getLocalizedMessage());
		} catch (TException e) {
			logger.severe("TException==>" + e.getLocalizedMessage());
		}
	}
}

同样,执行结果成功~

代码语言:javascript
复制
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Received 1
六月 08, 2017 7:51:12 下午 com.xxx.tutorial.thrift.client.UserClient2 main
信息: client.findUsersByName()方法結果 == >[User(userId:1, name:Wang), User(userId:2, name:Mengjun)]
Received 2
六月 08, 2017 7:51:12 下午 com.xxx.tutorial.thrift.client.UserClient2 main
信息: user saved result == > true
Received 3
六月 08, 2017 7:51:12 下午 com.xxx.tutorial.thrift.client.UserClient2 main
严重: UserNotFoundException==>userId=1002的用户不存在

小结

本教程主要帮助开发人员熟悉Thrift的IDL语法,并给出Java对应的示例,并给出几种不同的Server和Client端调用实现~

限于篇幅,AsyncIface和AsyncClient等会在后续的博文中补充上去~

另外,FaceBook也开源了Nifty

Nifty是facebook公司开源的,基于netty的thrift服务端和客户端实现。 详细资料可以参考Nifty官网【https://github.com/facebook/nifty/】

后续,也可以给出Nifty相关的示例~

代码下载

【https://pan.baidu.com/s/1c900r0】

参考文献

【1】https://media.readthedocs.org/pdf/thrift-tutorial/latest/thrift-tutorial.pdf

【2】https://diwakergupta.github.io/thrift-missing-guide/thrift.pdf

【3】http://dongxicheng.org/search-engine/thrift-guide/

【4】http://www.micmiu.com/soa/rpc/thrift-sample/

【5】http://blog.csdn.net/ITer_ZC/article/details/39695187

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 孟君的编程札记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Thrift简介
  • Thrift协议栈
    • Transport
    • Thrift简介
    • Thrift协议栈
      • Transport
        • Protocol
          • Processor
            • Server
            • Thrift类型系统
              • 基本类型(Base Type)
                • 特殊类型(Special type)
                  • 容器(container)
                    • 结构(struct)
                      • 异常(Exception)
                        • 服务(Service)
                        • 其它语法参考
                          • Typedefs
                            • 枚举Enums
                              • 注释Comments
                                • 命名空间Namespace
                                  • Includes
                                    • 常量Constants
                                    • 编写一个Thrift文件
                                      • 基本类型和特殊类型
                                        • 枚举类
                                          • 异常exception
                                            • 容器
                                              • 服务Service
                                              • 示例
                                                • 说明
                                                  • 产生代码
                                                    • 接口代码
                                                      • 实现代码
                                                        • TSimpleServer(阻塞IO)
                                                          • TThreadPoolServer(多线程阻塞IO)
                                                            • THsHaServer(多线程 NIO)
                                                            • 小结
                                                            • 代码下载
                                                            • 参考文献
                                                            相关产品与服务
                                                            容器服务
                                                            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                                                            领券
                                                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档