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接口提供的方法:

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接口提供的方法:

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只写协议, 生成的文件很容易通过脚本语言解析
  • 等等

主要的方法有:

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)

读操作~

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的结构体非常简单:

/** 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处理

示例:

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)

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

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

特殊类型(Special type)

binary   :未经过编码的字节流

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

容器(container)

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

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的概念~

如,

struct  User {  1:i32 userId,2:string name
}

异常(Exception)

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

如,

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

服务(Service)

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

格式如下,

service <name> {<returntype> <name> (<arguments>)[throws (<exceptions>)]
...
}

如,

service  UserService {string sayHello(1:string name);
}

其它语法参考

Typedefs

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

typedef i32 MyInteger

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

typedef i32 MyIntegerstruct  User {  1:MyInteger userId,2:string name
}

枚举Enums

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

enum Gender {MALE,FEMALE,UNKONWN
}

注释Comments

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

# 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:

namespace cpp com.example.project  // anamespace java com.example.project // b

Includes

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

include "user.thrift"namespace java com.xxx.tutorial.thrift.serviceservice  UserService {string sayHello(1:string name),bool saveUser(1:user.User user)
}

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

常量Constants

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

const i32 INT_CONST = 1234;    // aconst map<string,string> MAP_CONST = {"hello": "world", "goodnight": "moon"}

编写一个Thrift文件

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

基本类型和特殊类型

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

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文件,类型相关的部分代码如下:

/*** 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; // requiredpublic byte byteValue; // requiredpublic short shortValue; // requiredpublic int intValue; // requiredpublic long longValue; // requiredpublic double doubleValue; // requiredpublic java.lang.String stringValue; // requiredpublic 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_VALUEreturn BOOL_VALUE;case 2: // BYTE_VALUEreturn BYTE_VALUE;case 3: // SHORT_VALUEreturn SHORT_VALUE;case 4: // INT_VALUEreturn INT_VALUE;case 5: // LONG_VALUEreturn LONG_VALUE;case 6: // DOUBLE_VALUEreturn DOUBLE_VALUE;case 7: // STRING_VALUEreturn STRING_VALUE;case 8: // BINARY_VALUEreturn 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 assignmentsprivate 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);}@Overridepublic 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

enum Gender {MALE,FEMALE,UNKONWN
}

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

/*** 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文件,并写入如下几个属性~

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

根据exception.thrift生成java代码

/*** 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; // requiredpublic 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: // CODEreturn CODE;case 2: // MESSAGEreturn 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 assignmentspublic 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);}@Overridepublic 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();}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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);}@Overridepublic 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: // CODEif (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: // MESSAGEif (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 methodstruct.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> {@Overridepublic 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);}}@Overridepublic 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类, 会在集合类中使用~

namespace java com.xxx.tutorial.thrift.entity  /*** 用户类*/
struct  User {  1:i32 userId,2:string name
}  

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

include "user.thrift"namespace java com.xxx.tutorial.rpc.entitystruct ContainerTypes {1: list<string> stringValueList;   2: set<string> stringValueSet;3: map<string,string> stringValueMap;4: list<user.User> userList;}

根据thrift文件生成java代码~

/*** 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; // requiredpublic java.util.Set<java.lang.String> stringValueSet; // requiredpublic java.util.Map<java.lang.String,java.lang.String> stringValueMap; // requiredpublic 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_LISTreturn STRING_VALUE_LIST;case 2: // STRING_VALUE_SETreturn STRING_VALUE_SET;case 3: // STRING_VALUE_MAPreturn STRING_VALUE_MAP;case 4: // USER_LISTreturn USER_LIST;default:return null;}}... ... }

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

服务Service

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


namespace java com.xxx.tutorial.rpc.exceptionexception UserNotFoundException {1: string code;2: string message;
}

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

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代码

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获取用户列表以及删除用户,如:

 /*** 保存用户* * @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的内容如下:

/*** */
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,如:

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,

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模块编写客户端代码~

如:

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());}}
}

三个方法的结果都有了~

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)

服务端代码示例:

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();}}
}

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

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());}}
}

同样调用成功

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

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的描述如下:

/*** 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~

服务端代码示例如下:

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();}}
}

客户端代码如下:

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());}}
}

同样,执行结果成功~

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

Thrift使用教程(Java版本)相关推荐

  1. 跨平台通信中间件thrift学习【Java版本】(转)

    转自:http://neoremind.com/2012/03/%E8%B7%A8%E5%B9%B3%E5%8F%B0%E9%80%9A%E4%BF%A1%E4%B8%AD%E9%97%B4%E4%B ...

  2. java微信公众号开发教程_微信公众平台开发教程(java版本含代码) 中文PDF版 3.13MB...

    本文档将对即将推出的微信公众帐号开发系列连载教程做简单的说明. 教程主要是面向有一定 Java 编程基础的朋友, 目录: 微信公众帐号开发教程第 1 篇-引言  2 微信公众帐号开发教程第 2 篇-微 ...

  3. 【最新敲简单】浪漫微信早安推送 +页面总控,JAVA版本,一键部署运行——保姆级教程

    [最新敲简单]微信早安推送 +页面总控, JAVA版本,一键部署运行--保姆级教程 文章目录 [最新敲简单]微信早安推送 +页面总控, JAVA版本,一键部署运行--保姆级教程 一.项目简介 二.本地 ...

  4. java 画笔跟swing组件_Java学习教程(基础)--Java版本历史(二)

    Java语言自JDK1.0版本以来经历了许多次更新,也在基本程序库中增加了大量的类别和包.从J2SE 1.4开始,Java语言的变动由 Java Community Process(JCP)管理,JC ...

  5. java版本微信机器人使用教程V1.0

    大家好,我是雄雄,欢迎关注微信公众号雄雄的小课堂 现在是:2023年5月10日17:57:02 免费的云桌面,每个人都能领三个月,用来跑机器人还是很不错的,领取连接 前言 历经好多天,java版本的微 ...

  6. Thrift介绍以及Java中使用Thrift实现RPC示例

    场景 Thrift Thrift最初由Facebook研发,主要用于各个服务之间的RPC通信,支持跨语言,常用的语言比如C++, Java, Python,PHP, Ruby, Erlang,Perl ...

  7. java demo在哪里下载_[Java教程]Java学习 (一)、下载,配置环境变量,第一个demo...

    [Java教程]Java学习 (一).下载,配置环境变量,第一个demo 0 2016-03-01 22:00:18 一.在 http://www.oracle.com 下载java JDK 安装到自 ...

  8. Thrift中实现Java与Python的RPC互相调用

    场景 Thrift介绍以及Java中使用Thrift实现RPC示例: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1086894 ...

  9. Eclipse Collections随Java版本的演变

    \ 本文要点 \\ Eclipse Collections是一个高性能的Java集合框架,针对Java 8及以上版本进行了重新设计,极大地丰富了这个Java Collections框架的功能.\\t ...

最新文章

  1. 大话数据结构(十)java程序——队列
  2. 绕过360安全卫士的部分代码
  3. linux CentOS7最小化安装环境静默安装Oracle11GR2数据库(配置数据库监听_09)
  4. @async 如何返回list_图解 Await 和 Async
  5. Hello log4net——做一个实用好用的log4net的demo(转)
  6. java md5加密解密类_Java实现MD5加密解密类
  7. ccy 朴素版(顺序搜索)19ms
  8. Ubuntu安装Google Chrome浏览器
  9. Loadrunner报错汇总
  10. 网页中图片显示不出来,解决网页中图片不能显示的方法
  11. 【每日一题】递增序列中绝对值最小的数
  12. 服务器连接不上的处理方式
  13. 小米手机小技巧:小米手机心率测试
  14. 微博、微信上的假消息害苦了哥
  15. 金水智能汽车5G-V2X车路协同安全测试认证基地项目招标文件
  16. 获取当天年月日,及开始结束时间
  17. 【AI语音】九联UNT402A_通刷_纯净精简_免费线刷固件包
  18. Kubernetes API Aggregation在 Master 的 API Server 中启用 API 聚合功能注册自定义 APIService 资源实现和部署自定义的 API Serv
  19. Nature Neuroscience综述:网络神经系统中的动态表征
  20. 三国群雄传ol服务器 修改,三国群雄传四大兵营进阶改造攻略详解

热门文章

  1. 软工个人作业-提问回顾与个人总结
  2. Dubbo——Dubbo中的常用标签、服务化最佳实践
  3. Mac 装win系统
  4. 静态路由切换及探测配置
  5. poj3232 - Accelerator(加速器)
  6. mac下图形界面开发:ios and mac osx
  7. c++ 沉思录笔记——句柄(第一部分)
  8. 可视化神器Plotly玩转股票图
  9. 我的2017云栖之行
  10. JavaScript 实战-翻牌游戏 - H5和CSS3 (1)