Apache Thrift 是FaceBook实现的一种跨平台的远程服务调用(RPC)的框架。它采用接口描述语言(IDL)定义并创建服务,传输数据采用二进制格式,相对于XML和Json等常用数据传输方式体积更小。
首先一个完整的RPC模块主要分三部分:
1.服务层(service):RPC接口的定义与实现
2.协议层(protocol):RPC报文格式和数据编码格式
3.传输层(transport):实现底层的通信(如socket)以及系统相关的功能(如事件循环、多线程)
如上图所示,图中黄色部分是用户实现的业务逻辑,褐色部分是根据Thrift定义的服务接口描述文件生成的客户端和服务端代码框架,红色部分是根据Thrift文件生成代码实现数据的读写操作。红色部分以下是Thrift的传输体系、协议以及底层的I/O通信。
一个thrift简单实例过程:
1.写Thrift定义文件(.thrift)
namespace java com.eviac.blog.samples.thrift.server // defines the namespace typedef i32 int //typedefs to get convenient names for your types service AdditionService { // defines the service to add two numbers
int add(1:int n1, 2:int n2), //defines a method
}
2.编译Thrift定义文件
thrift --gen <language> <Thrift filename>
对于java语言来说就是:
thrift --gen java add.thrift
执行完之后,在gen-java目录下你会发现构建RPC服务器和客户端有用的源代码,在本例中将生成一个AddtionService.java的文件。
现将生成的代码贴上:
/**
* Autogenerated by Thrift Compiler (0.8.0-xsb)
*
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
* @generated
*/ import org.apache.thrift.scheme.IScheme;
import org.apache.thrift.scheme.SchemeFactory;
import org.apache.thrift.scheme.StandardScheme; import org.apache.thrift.scheme.TupleScheme;
import org.apache.thrift.protocol.TTupleProtocol;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.EnumMap;
import java.util.Set;
import java.util.HashSet;
import java.util.EnumSet;
import java.util.Collections;
import java.util.BitSet;
import java.nio.ByteBuffer;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class AdditionService { public interface Iface { public int add(int n1, int n2) throws org.apache.thrift.TException; } public interface AsyncIface { public void add(int n1, int n2, org.apache.thrift.async.AsyncMethodCallback<AsyncClient.add_call> 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 int add(int n1, int n2) throws org.apache.thrift.TException
{
send_add(n1, n2);
return recv_add();
} public void send_add(int n1, int n2) throws org.apache.thrift.TException
{
add_args args = new add_args();
args.setN1(n1);
args.setN2(n2);
sendBase("add", args);
} public int recv_add() throws org.apache.thrift.TException
{
add_result result = new add_result();
receiveBase(result, "add");
if (result.isSetSuccess()) {
return result.success;
}
throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "add failed: unknown result");
} }
public static class AsyncClient extends org.apache.thrift.async.TAsyncClient implements AsyncIface {
public static class Factory implements org.apache.thrift.async.TAsyncClientFactory<AsyncClient> {
private org.apache.thrift.async.TAsyncClientManager clientManager;
private org.apache.thrift.protocol.TProtocolFactory protocolFactory;
public Factory(org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.protocol.TProtocolFactory protocolFactory) {
this.clientManager = clientManager;
this.protocolFactory = protocolFactory;
}
public AsyncClient getAsyncClient(org.apache.thrift.transport.TNonblockingTransport transport) {
return new AsyncClient(protocolFactory, clientManager, transport);
}
} public AsyncClient(org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.transport.TNonblockingTransport transport) {
super(protocolFactory, clientManager, transport);
} public void add(int n1, int n2, org.apache.thrift.async.AsyncMethodCallback<add_call> resultHandler) throws org.apache.thrift.TException {
checkReady();
add_call method_call = new add_call(n1, n2, resultHandler, this, ___protocolFactory, ___transport);
this.___currentMethod = method_call;
___manager.call(method_call);
} public static class add_call extends org.apache.thrift.async.TAsyncMethodCall {
private int n1;
private int n2;
public add_call(int n1, int n2, org.apache.thrift.async.AsyncMethodCallback<add_call> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
super(client, protocolFactory, transport, resultHandler, false);
this.n1 = n1;
this.n2 = n2;
} public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("add", org.apache.thrift.protocol.TMessageType.CALL, 0));
add_args args = new add_args();
args.setN1(n1);
args.setN2(n2);
args.write(prot);
prot.writeMessageEnd();
} public int getResult() throws org.apache.thrift.TException {
if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
throw new IllegalStateException("Method call not finished!");
}
org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
return (new Client(prot)).recv_add();
}
} } public static class Processor<I extends Iface> extends org.apache.thrift.TBaseProcessor<I> implements org.apache.thrift.TProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger(Processor.class.getName());
public Processor(I iface) {
super(iface, getProcessMap(new HashMap<String, org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>>()));
} protected Processor(I iface, Map<String, org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>> processMap) {
super(iface, getProcessMap(processMap));
} private static <I extends Iface> Map<String, org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>> getProcessMap(Map<String, org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>> processMap) {
processMap.put("add", new add());
return processMap;
} private static class add<I extends Iface> extends org.apache.thrift.ProcessFunction<I, add_args> {
public add() {
super("add");
} protected add_args getEmptyArgsInstance() {
return new add_args();
} protected boolean isOneway() {
return false;
} protected add_result getResult(I iface, add_args args) throws org.apache.thrift.TException {
add_result result = new add_result();
result.success = iface.add(args.n1, args.n2);
result.setSuccessIsSet(true);
return result;
}
} } public static class add_args implements org.apache.thrift.TBase<add_args, add_args._Fields>, java.io.Serializable, Cloneable {
private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("add_args"); private static final org.apache.thrift.protocol.TField N1_FIELD_DESC = new org.apache.thrift.protocol.TField("n1", org.apache.thrift.protocol.TType.I32, (short)1);
private static final org.apache.thrift.protocol.TField N2_FIELD_DESC = new org.apache.thrift.protocol.TField("n2", org.apache.thrift.protocol.TType.I32, (short)2); private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
static {
schemes.put(StandardScheme.class, new add_argsStandardSchemeFactory());
schemes.put(TupleScheme.class, new add_argsTupleSchemeFactory());
} public int n1; // required
public int n2; // 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 {
N1((short)1, "n1"),
N2((short)2, "n2"); private static final Map<String, _Fields> byName = new HashMap<String, _Fields>(); static {
for (_Fields field : 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: // N1
return N1;
case 2: // N2
return N2;
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 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(String name) {
return byName.get(name);
} private final short _thriftId;
private final String _fieldName; _Fields(short thriftId, String fieldName) {
_thriftId = thriftId;
_fieldName = fieldName;
} public short getThriftFieldId() {
return _thriftId;
} public String getFieldName() {
return _fieldName;
}
} // isset id assignments
private static final int __N1_ISSET_ID = 0;
private static final int __N2_ISSET_ID = 1;
private BitSet __isset_bit_vector = new BitSet(2);
public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
static {
Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
tmpMap.put(_Fields.N1, new org.apache.thrift.meta_data.FieldMetaData("n1", org.apache.thrift.TFieldRequirementType.DEFAULT,
new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32 , "int")));
tmpMap.put(_Fields.N2, new org.apache.thrift.meta_data.FieldMetaData("n2", org.apache.thrift.TFieldRequirementType.DEFAULT,
new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32 , "int")));
metaDataMap = Collections.unmodifiableMap(tmpMap);
org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(add_args.class, metaDataMap);
} public add_args() {
} public add_args(
int n1,
int n2)
{
this();
this.n1 = n1;
setN1IsSet(true);
this.n2 = n2;
setN2IsSet(true);
} /**
* Performs a deep copy on <i>other</i>.
*/
public add_args(add_args other) {
__isset_bit_vector.clear();
__isset_bit_vector.or(other.__isset_bit_vector);
this.n1 = other.n1;
this.n2 = other.n2;
} public add_args deepCopy() {
return new add_args(this);
} @Override
public void clear() {
setN1IsSet(false);
this.n1 = 0;
setN2IsSet(false);
this.n2 = 0;
} public int getN1() {
return this.n1;
} public add_args setN1(int n1) {
this.n1 = n1;
setN1IsSet(true);
return this;
} public void unsetN1() {
__isset_bit_vector.clear(__N1_ISSET_ID);
} /** Returns true if field n1 is set (has been assigned a value) and false otherwise */
public boolean isSetN1() {
return __isset_bit_vector.get(__N1_ISSET_ID);
} public void setN1IsSet(boolean value) {
__isset_bit_vector.set(__N1_ISSET_ID, value);
} public int getN2() {
return this.n2;
} public add_args setN2(int n2) {
this.n2 = n2;
setN2IsSet(true);
return this;
} public void unsetN2() {
__isset_bit_vector.clear(__N2_ISSET_ID);
} /** Returns true if field n2 is set (has been assigned a value) and false otherwise */
public boolean isSetN2() {
return __isset_bit_vector.get(__N2_ISSET_ID);
} public void setN2IsSet(boolean value) {
__isset_bit_vector.set(__N2_ISSET_ID, value);
} public void setFieldValue(_Fields field, Object value) {
switch (field) {
case N1:
if (value == null) {
unsetN1();
} else {
setN1((Integer)value);
}
break; case N2:
if (value == null) {
unsetN2();
} else {
setN2((Integer)value);
}
break; }
} public Object getFieldValue(_Fields field) {
switch (field) {
case N1:
return Integer.valueOf(getN1()); case N2:
return Integer.valueOf(getN2()); }
throw new 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 IllegalArgumentException();
} switch (field) {
case N1:
return isSetN1();
case N2:
return isSetN2();
}
throw new IllegalStateException();
} @Override
public boolean equals(Object that) {
if (that == null)
return false;
if (that instanceof add_args)
return this.equals((add_args)that);
return false;
} public boolean equals(add_args that) {
if (that == null)
return false; boolean this_present_n1 = true;
boolean that_present_n1 = true;
if (this_present_n1 || that_present_n1) {
if (!(this_present_n1 && that_present_n1))
return false;
if (this.n1 != that.n1)
return false;
} boolean this_present_n2 = true;
boolean that_present_n2 = true;
if (this_present_n2 || that_present_n2) {
if (!(this_present_n2 && that_present_n2))
return false;
if (this.n2 != that.n2)
return false;
} return true;
} @Override
public int hashCode() {
return 0;
} public int compareTo(add_args other) {
if (!getClass().equals(other.getClass())) {
return getClass().getName().compareTo(other.getClass().getName());
} int lastComparison = 0;
add_args typedOther = (add_args)other; lastComparison = Boolean.valueOf(isSetN1()).compareTo(typedOther.isSetN1());
if (lastComparison != 0) {
return lastComparison;
}
if (isSetN1()) {
lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.n1, typedOther.n1);
if (lastComparison != 0) {
return lastComparison;
}
}
lastComparison = Boolean.valueOf(isSetN2()).compareTo(typedOther.isSetN2());
if (lastComparison != 0) {
return lastComparison;
}
if (isSetN2()) {
lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.n2, typedOther.n2);
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 {
schemes.get(iprot.getScheme()).getScheme().read(iprot, this);
} public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
schemes.get(oprot.getScheme()).getScheme().write(oprot, this);
} @Override
public String toString() {
StringBuilder sb = new StringBuilder("add_args(");
boolean first = true; sb.append("n1:");
sb.append(this.n1);
first = false;
if (!first) sb.append(", ");
sb.append("n2:");
sb.append(this.n2);
first = false;
sb.append(")");
return sb.toString();
} public void validate() throws org.apache.thrift.TException {
// check for required fields
} 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, ClassNotFoundException {
try {
// it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor.
__isset_bit_vector = new BitSet(1);
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 add_argsStandardSchemeFactory implements SchemeFactory {
public add_argsStandardScheme getScheme() {
return new add_argsStandardScheme();
}
} private static class add_argsStandardScheme extends StandardScheme<add_args> { public void read(org.apache.thrift.protocol.TProtocol iprot, add_args 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: // N1
if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
struct.n1 = iprot.readI32();
struct.setN1IsSet(true);
} else {
org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
}
break;
case 2: // N2
if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
struct.n2 = iprot.readI32();
struct.setN2IsSet(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, add_args struct) throws org.apache.thrift.TException {
struct.validate(); oprot.writeStructBegin(STRUCT_DESC);
oprot.writeFieldBegin(N1_FIELD_DESC);
oprot.writeI32(struct.n1);
oprot.writeFieldEnd();
oprot.writeFieldBegin(N2_FIELD_DESC);
oprot.writeI32(struct.n2);
oprot.writeFieldEnd();
oprot.writeFieldStop();
oprot.writeStructEnd();
} } private static class add_argsTupleSchemeFactory implements SchemeFactory {
public add_argsTupleScheme getScheme() {
return new add_argsTupleScheme();
}
} private static class add_argsTupleScheme extends TupleScheme<add_args> { @Override
public void write(org.apache.thrift.protocol.TProtocol prot, add_args struct) throws org.apache.thrift.TException {
TTupleProtocol oprot = (TTupleProtocol) prot;
BitSet optionals = new BitSet();
if (struct.isSetN1()) {
optionals.set(0);
}
if (struct.isSetN2()) {
optionals.set(1);
}
oprot.writeBitSet(optionals, 2);
if (struct.isSetN1()) {
oprot.writeI32(struct.n1);
}
if (struct.isSetN2()) {
oprot.writeI32(struct.n2);
}
} @Override
public void read(org.apache.thrift.protocol.TProtocol prot, add_args struct) throws org.apache.thrift.TException {
TTupleProtocol iprot = (TTupleProtocol) prot;
BitSet incoming = iprot.readBitSet(2);
if (incoming.get(0)) {
struct.n1 = iprot.readI32();
struct.setN1IsSet(true);
}
if (incoming.get(1)) {
struct.n2 = iprot.readI32();
struct.setN2IsSet(true);
}
}
} } public static class add_result implements org.apache.thrift.TBase<add_result, add_result._Fields>, java.io.Serializable, Cloneable {
private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("add_result"); private static final org.apache.thrift.protocol.TField SUCCESS_FIELD_DESC = new org.apache.thrift.protocol.TField("success", org.apache.thrift.protocol.TType.I32, (short)0); private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
static {
schemes.put(StandardScheme.class, new add_resultStandardSchemeFactory());
schemes.put(TupleScheme.class, new add_resultTupleSchemeFactory());
} public int success; // 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 {
SUCCESS((short)0, "success"); private static final Map<String, _Fields> byName = new HashMap<String, _Fields>(); static {
for (_Fields field : 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 0: // SUCCESS
return SUCCESS;
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 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(String name) {
return byName.get(name);
} private final short _thriftId;
private final String _fieldName; _Fields(short thriftId, String fieldName) {
_thriftId = thriftId;
_fieldName = fieldName;
} public short getThriftFieldId() {
return _thriftId;
} public String getFieldName() {
return _fieldName;
}
} // isset id assignments
private static final int __SUCCESS_ISSET_ID = 0;
private BitSet __isset_bit_vector = new BitSet(1);
public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
static {
Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
tmpMap.put(_Fields.SUCCESS, new org.apache.thrift.meta_data.FieldMetaData("success", org.apache.thrift.TFieldRequirementType.DEFAULT,
new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32 , "int")));
metaDataMap = Collections.unmodifiableMap(tmpMap);
org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(add_result.class, metaDataMap);
} public add_result() {
} public add_result(
int success)
{
this();
this.success = success;
setSuccessIsSet(true);
} /**
* Performs a deep copy on <i>other</i>.
*/
public add_result(add_result other) {
__isset_bit_vector.clear();
__isset_bit_vector.or(other.__isset_bit_vector);
this.success = other.success;
} public add_result deepCopy() {
return new add_result(this);
} @Override
public void clear() {
setSuccessIsSet(false);
this.success = 0;
} public int getSuccess() {
return this.success;
} public add_result setSuccess(int success) {
this.success = success;
setSuccessIsSet(true);
return this;
} public void unsetSuccess() {
__isset_bit_vector.clear(__SUCCESS_ISSET_ID);
} /** Returns true if field success is set (has been assigned a value) and false otherwise */
public boolean isSetSuccess() {
return __isset_bit_vector.get(__SUCCESS_ISSET_ID);
} public void setSuccessIsSet(boolean value) {
__isset_bit_vector.set(__SUCCESS_ISSET_ID, value);
} public void setFieldValue(_Fields field, Object value) {
switch (field) {
case SUCCESS:
if (value == null) {
unsetSuccess();
} else {
setSuccess((Integer)value);
}
break; }
} public Object getFieldValue(_Fields field) {
switch (field) {
case SUCCESS:
return Integer.valueOf(getSuccess()); }
throw new 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 IllegalArgumentException();
} switch (field) {
case SUCCESS:
return isSetSuccess();
}
throw new IllegalStateException();
} @Override
public boolean equals(Object that) {
if (that == null)
return false;
if (that instanceof add_result)
return this.equals((add_result)that);
return false;
} public boolean equals(add_result that) {
if (that == null)
return false; boolean this_present_success = true;
boolean that_present_success = true;
if (this_present_success || that_present_success) {
if (!(this_present_success && that_present_success))
return false;
if (this.success != that.success)
return false;
} return true;
} @Override
public int hashCode() {
return 0;
} public int compareTo(add_result other) {
if (!getClass().equals(other.getClass())) {
return getClass().getName().compareTo(other.getClass().getName());
} int lastComparison = 0;
add_result typedOther = (add_result)other; lastComparison = Boolean.valueOf(isSetSuccess()).compareTo(typedOther.isSetSuccess());
if (lastComparison != 0) {
return lastComparison;
}
if (isSetSuccess()) {
lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.success, typedOther.success);
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 {
schemes.get(iprot.getScheme()).getScheme().read(iprot, this);
} public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
schemes.get(oprot.getScheme()).getScheme().write(oprot, this);
} @Override
public String toString() {
StringBuilder sb = new StringBuilder("add_result(");
boolean first = true; sb.append("success:");
sb.append(this.success);
first = false;
sb.append(")");
return sb.toString();
} public void validate() throws org.apache.thrift.TException {
// check for required fields
} 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, 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 add_resultStandardSchemeFactory implements SchemeFactory {
public add_resultStandardScheme getScheme() {
return new add_resultStandardScheme();
}
} private static class add_resultStandardScheme extends StandardScheme<add_result> { public void read(org.apache.thrift.protocol.TProtocol iprot, add_result 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 0: // SUCCESS
if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
struct.success = iprot.readI32();
struct.setSuccessIsSet(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, add_result struct) throws org.apache.thrift.TException {
struct.validate(); oprot.writeStructBegin(STRUCT_DESC);
oprot.writeFieldBegin(SUCCESS_FIELD_DESC);
oprot.writeI32(struct.success);
oprot.writeFieldEnd();
oprot.writeFieldStop();
oprot.writeStructEnd();
} } private static class add_resultTupleSchemeFactory implements SchemeFactory {
public add_resultTupleScheme getScheme() {
return new add_resultTupleScheme();
}
} private static class add_resultTupleScheme extends TupleScheme<add_result> { @Override
public void write(org.apache.thrift.protocol.TProtocol prot, add_result struct) throws org.apache.thrift.TException {
TTupleProtocol oprot = (TTupleProtocol) prot;
BitSet optionals = new BitSet();
if (struct.isSetSuccess()) {
optionals.set(0);
}
oprot.writeBitSet(optionals, 1);
if (struct.isSetSuccess()) {
oprot.writeI32(struct.success);
}
} @Override
public void read(org.apache.thrift.protocol.TProtocol prot, add_result struct) throws org.apache.thrift.TException {
TTupleProtocol iprot = (TTupleProtocol) prot;
BitSet incoming = iprot.readBitSet(1);
if (incoming.get(0)) {
struct.success = iprot.readI32();
struct.setSuccessIsSet(true);
}
}
} } }
3.写一个service handler(也可以叫serviceImpl)
Service handler 类必须实现 AdditionService.Iface接口。AdditionServiceHandler.java代码如下:
import org.apache.thrift.TException; public class AdditionServiceHandler implements AdditionService.Iface{ @Override
public int add(int n1, int n2) throws TException {
// TODO Auto-generated method stub
return n1 + n2;
} }
4.写一个简单的服务器
下面的示例代码是一个简单的Thrift服务器。可以看到下面的代码中有一段是注释了的,可以去掉注释来启用多线程服务器。
示例服务器(MyServer.java)
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TServer.Args;
import org.apache.thrift.server.TSimpleServer; public class MyServer { public static void StartsimpleServer(AdditionService.Processor<AdditionServiceHandler> processor) {
try {
TServerTransport serverTransport = new TServerSocket(9090);
TServer server = new TSimpleServer(
new Args(serverTransport).processor(processor)); // Use this for a multithreaded server
// TServer server = new TThreadPoolServer(new
// TThreadPoolServer.Args(serverTransport).processor(processor)); System.out.println("Starting the simple server...");
server.serve();
} catch (Exception e) {
e.printStackTrace();
}
} public static void main(String[] args) {
StartsimpleServer(new AdditionService.Processor<AdditionServiceHandler>(new AdditionServiceHandler()));
} }
5.写一个简单的客户端
下面的例子是一个使用Java写的客户端短使用AdditionService的服务。
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; public class AdditionClient { public static void main(String[] args) { try {
TTransport transport; transport = new TSocket("localhost", 9090);
transport.open(); TProtocol protocol = new TBinaryProtocol(transport);
AdditionService.Client client = new AdditionService.Client(protocol); System.out.println(client.add(100, 200)); transport.close();
} catch (TTransportException e) {
e.printStackTrace();
} catch (TException x) {
x.printStackTrace();
}
} }
运行服务端代码(MyServer.java)将会看到下面的输出。
Starting the simple server...
然后运行客户端代码(AdditionClient.java),将会看到如下输出。
300
Thrift主要由五个部分组成:
系统类型以及IDL编译器:负责由用户给定的IDL文件生成相应语言的接口代码。
Tprotocol:实现RPC的协议层,可以选择多种不同的对象串行化方式,如JSON,Binary.
Transport:实现RPC的传输层,同样可以选择不同的传输层实现,如socket,非阻塞的socket等。
Tprocessor:作为协议层和用户提供的服务实现之间的纽带,负责调用服务实现的接口。
Tserver:聚合TProtocol,TTransport和TProcessor几个对象。
上述的这5个部件都是在 Thrift 的源代码中通过为不同语言提供库来实现的,这些库的代码在 Thrift 源码目录的 lib 目录下面,在使用 Thrift 之前需要先熟悉与自己的语言对应的库提供的接口。
数据类型
Thrift 脚本可定义的数据类型包括以下几种类型:
- 基本类型:
- bool:布尔值,true 或 false,对应 Java 的 boolean
- byte:8 位有符号整数,对应 Java 的 byte
- i16:16 位有符号整数,对应 Java 的 short
- i32:32 位有符号整数,对应 Java 的 int
- i64:64 位有符号整数,对应 Java 的 long
- double:64 位浮点数,对应 Java 的 double
- string:未知编码文本或二进制字符串,对应 Java 的 String
- 结构体类型:
- struct:定义公共的对象,类似于 C 语言中的结构体定义,在 Java 中是一个 JavaBean
- 容器类型:
- list:对应 Java 的 ArrayList
- set:对应 Java 的 HashSet
- map:对应 Java 的 HashMap
- 异常类型:
- exception:对应 Java 的 Exception
- 服务类型:
- service:对应服务的类
协议
Thrift 可以让用户选择客户端与服务端之间传输通信协议的类别,在传输协议上总体划分为文本 (text) 和二进制 (binary) 传输协议,为节约带宽,提高传输效率,一般情况下使用二进制类型的传输协议为多数,有时还会使用基于文本类型的协议,这需要根据项目 / 产品中的实际需求。常用协议有以下几种:
TBinaryProtocol —— 二进制编码格式进行数据传输
TCompactProtocol —— 高效率的、密集的二进制编码格式进行数据传输
TJSONProtocol —— 使用 JSON 的数据编码协议进行数据传输
TSimpleJSONProtocol —— 只提供 JSON 只写的协议,适用于通过脚本语言解析
传输层
常用的传输层有以下几种:
1.TSocket —— 使用阻塞式 I/O 进行传输,是最常见的模式
2.TFramedTransport —— 使用非阻塞方式,按块的大小进行传输,类似于 Java 中的 NIO
若使用 TFramedTransport 传输层,其服务器必须修改为非阻塞的服务类型,TNonblockingServerTransport 类是构建非阻塞 socket 的抽象类,TNonblockingServerSocket 类继承 TNonblockingServerTransport
3.TNonblockingTransport —— 使用非阻塞方式,用于构建异步客户端
服务端类型
常见的服务端类型有以下几种:
1.TSimpleServer —— 单线程服务器端使用标准的阻塞式 I/O
2.TThreadPoolServer —— 多线程服务器端使用标准的阻塞式 I/O
3.TNonblockingServer —— 多线程服务器端使用非阻塞式 I/O
本文参考以及引用:http://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/
http://my.oschina.net/jack230230/blog/66041