在之前的一篇博文一步步完成thrift rpc示例中,给出了一个使用thrift完成rpc的示例。
在本篇文章,我们会给出一个使用Thrift的基本教程。
Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目。Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(目前支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),并由生成的代码负责RPC协议层和传输层的实现。
Thrift 客户端、服务端API架构如下图所示:
图片来自https://en.wikipedia.org/wiki/Apache_Thrift
Thrift的网络栈如下所示:
Transport层提供了一个简单的网络读写抽象层。这使得thrift底层的transport从系统其它部分(如:序列化/反序列化)解耦。以下是一些Transport接口提供的方法:
open
close
read
write
flush
更加详细方法如,
Thrift支持如下几种Transport:
在之前的一篇博文【一步一步完成thrift Java示例】中,给出了一个使用thrift完成rpc的示例。
在本篇博文,我们会给出一个使用Thrift的基本教程~
Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目。Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(目前支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),并由生成的代码负责RPC协议层和传输层的实现。
Thrift 客户端、服务端API架构如下图所示:
图片来自https://en.wikipedia.org/wiki/Apache_Thrift
Thrift的网络栈如下所示:
Transport层提供了一个简单的网络读写抽象层。这使得thrift底层的transport从系统其它部分(如:序列化/反序列化)解耦。以下是一些Transport接口提供的方法:
open
close
read
write
flush
更加详细方法如,
Thrift支持如下几种Transport:
Protocol抽象层定义了一种将内存中数据结构映射成可传输格式的机制。换句话说,Protocol定义了datatype怎样使用底层的Transport对自己进行编解码。因此,Protocol的实现要给出编码机制并负责对数据进行序列化。
Thrift支持如下几种protocols:
主要的方法有:
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封装了从输入数据流中读数据和向数据数据流中写数据的操作。读写数据流用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实现的几个步骤如下~
(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类型系统包括预定义的基本类型(如bool , byte, double, string)、特殊类型(如binary)、用户自定义结构体(看上去像C 语言的结构体)、容器类型(如list,set,map)以及异常和服务定义~
bool :布尔类型(true or value),占一个字节
byte/i8 :有符号字节
i16 : 16位有符号整型
i32 : 32位有符号整型
i64 : 64位有符号整型
double :64位浮点数
string :未知编码或者二进制的字符串
注意, thrift不支持无符号整型,因为很多目标语言不存在无符号整型(如java)。
binary :未经过编码的字节流
Thrift基本类型、特殊类型和Java类型的对应关系如下表所示:
Thrift容器与类型密切相关,它与当前流行编程语言提供的容器类型相对应,Thrift提供了3种容器类型:
List<t1> :一系列t1类型的元素组成的有序表,元素可以重复
Set<t1> :一系列t1类型的元素组成的无序表,元素唯一
Map<t1,t2> :key/value对(key的类型是t1且key唯一,value类型是t2)
注意: 容器中的元素类型可以是除了service之外的任何合法thrift类型(包括结构体和异常)。
Thrift容器类型和Java类型的对应关系如下表所示:
Thrift结构体在概念上同C语言结构体类型—-一种将相关属性聚集(封装)在一起的方式。在面向对象语言中,thrift结构体被转换成类,在Java语言中,这等价于JavaBean的概念~
如,
struct User {
1:i32 userId,
2:string name
}
异常在语法和功能上类似于结构体,只不过异常使用关键字exception而不是struct关键字声明。 但它在语义上不同于结构体—当定义一个RPC服务时,开发者可能需要声明一个远程方法抛出一个异常。
如,
exception MyException {
1: string code;
2: string message;
}
一个服务包含一系列命名函数,每个函数包含一系列的参数以及一个返回类型。 在语法上,服务等价于定义一个接口或者纯虚抽象类~
格式如下,
service <name> {
<returntype> <name> (<arguments>)
[throws (<exceptions>)]
...
}
如,
service UserService {
string sayHello(1:string name);
}
Thrift支持C/C++风格的typedef, 如
typedef i32 MyInteger
说明: a. 末尾没有逗号 b. struct可以使用typedef
typedef i32 MyInteger
struct User {
1:MyInteger userId,
2:string name
}
可以像C/C++那样定义枚举类型,如:
enum Gender {
MALE,
FEMALE,
UNKONWN
}
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.
Thrift中的命名空间同C++中的namespace和java中的package类似,它们均提供了一种组织(隔离)代码的方式。因为每种语言均有自己的命名空间定义方式(如python中有module),thrift允许开发者针对特定语言定义namespace:
namespace cpp com.example.project // a
namespace java com.example.project // b
Thrift允许thrift文件包含,用户需要使用thrift文件名作为前缀访问被包含的对象,如:
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前缀
Thrift允许用户定义常量,复杂的类型和结构体可使用JSON形式表示。
const i32 INT_CONST = 1234; // a
const map<string,string> MAP_CONST = {"hello": "world", "goodnight": "moon"}
有了上述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; // 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
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.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; // 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类, 会在集合类中使用~
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.entity
struct 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; // 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类型之后,与下图展示的内容一致~
编写一个exception.thrift, 用于自定义异常类~
namespace java com.xxx.tutorial.rpc.exception
exception 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端调用的代码~
在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的示例就完成了~
服务端代码示例:
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的描述如下:
/**
* 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