IDL 生成文件
IDL 生成文件在 thrift 栈中的位置。
对于如下的 thrift :
namespace java com.meituan.service
service HelloService
{
string sayHello(1:string username)
}
生成:
// thrift 0.8.0
public class HelloService {
public interface Iface{
public String sayHello(String username) throws org.apache.thrift.TException;
}
public interface AsyncIface{
public void sayHello(String username, org.apache.thrift.async.AsyncMethodCallback<AsyncClient.sayHello_call> resultHandler) throws org.apache.thrift.TException;
}
public static class Client extends org.apache.thrift.TServiceClient implements Iface {}
public static class AsyncClient extends org.apache.thrift.async.TAsyncClient implements AsyncIface {}
public static class Processor<I extends Iface> extends org.apache.thrift.TBaseProcessor<I> implements org.apache.thrift.TProcessor {}
public static class sayHello_args implements org.apache.thrift.TBase<sayHello_args, sayHello_args._Fields>, java.io.Serializable, Cloneable {}
public static class sayHello_result implements org.apache.thrift.TBase<sayHello_result, sayHello_result._Fields>, java.io.Serializable, Cloneable {}
}
Iface & AsyncIface
接口类型被服务器和客户端共同使用。服务器端使用它来做顶层接口,编写实现类。客户端代码使用它作为生成代理的服务接口。
自动生成的接口有两个,一个是同步调用的Iface,一个是异步调用的AsyncIface。异步调用的接口多了一个回调参数。
public interface AsyncMethodCallback<T> {
public void onComplete(T response);
public void onError(Exception exception);
}
Client & AsyncClient
public static class Client extends org.apache.thrift.TServiceClient implements Iface {
// Client 工厂类
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);
}
// Iface.sayHello 的实现
public String sayHello(String username) throws org.apache.thrift.TException
{
send_sayHello(username);
return recv_sayHello();
}
public void send_sayHello(String username) throws org.apache.thrift.TException
{
// 方法参数的封装类
sayHello_args args = new sayHello_args();
args.setUsername(username);
//
sendBase("sayHello", args);
}
public String recv_sayHello() throws org.apache.thrift.TException
{
// 方法返回值的封装类
sayHello_result result = new sayHello_result();
//
receiveBase(result, "sayHello");
if (result.isSetSuccess()) {
return result.success;
}
throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "sayHello failed: unknown result");
}
}
参数的发送和结果的返回委托给 TServiceClient 来处理
public abstract class TServiceClient {
public TServiceClient(TProtocol prot) {
this(prot, prot);
}
public TServiceClient(TProtocol iprot, TProtocol oprot) {
iprot_ = iprot;
oprot_ = oprot;
}
protected TProtocol iprot_;
protected TProtocol oprot_;
protected int seqid_;
public TProtocol getInputProtocol() {
return this.iprot_;
}
public TProtocol getOutputProtocol() {
return this.oprot_;
}
protected void sendBase(String methodName, TBase args) throws TException {
// 发送消息头
oprot_.writeMessageBegin(new TMessage(methodName, TMessageType.CALL, ++seqid_));
// 发送消息体,由方法参数对象自己处理编解码
args.write(oprot_);
oprot_.writeMessageEnd();
oprot_.getTransport().flush();
}
protected void receiveBase(TBase result, String methodName) throws TException {
// 接收消息头
TMessage msg = iprot_.readMessageBegin();
if (msg.type == TMessageType.EXCEPTION) {
TApplicationException x = TApplicationException.read(iprot_);
iprot_.readMessageEnd();
throw x;
}
if (msg.seqid != seqid_) {
throw new TApplicationException(TApplicationException.BAD_SEQUENCE_ID, methodName + " failed: out of sequence response");
}
// 由返回值对象自己处理编解码
result.read(iprot_);
iprot_.readMessageEnd();
}
}
// TServiceClient 的工厂类
public interface TServiceClientFactory<T extends TServiceClient> {
public T getClient(TProtocol prot);
public T getClient(TProtocol iprot, TProtocol oprot);
}
Processor
用来支持方法调用,每个服务的实现类都要使用Processor来注册,这样最后服务器端调用接口实现时能定位到具体的实现类。
sayHello_args
方法参数的封装类。
sayHello_args 继承了 TBase,其中包含请求参数的编解码方法 read & write。
public interface TBase<T extends TBase<?,?>, F extends TFieldIdEnum> extends Comparable<T>, Serializable {
public void read(TProtocol iprot) throws TException;
public void write(TProtocol oprot) throws TException;
public F fieldForId(int fieldId);
public boolean isSet(F field);
public Object getFieldValue(F field);
public void setFieldValue(F field, Object value);
public TBase<T, F> deepCopy();
public void clear();
}
private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<>();
static {
schemes.put(StandardScheme.class, new sayHello_argsStandardSchemeFactory());
schemes.put(TupleScheme.class, new sayHello_argsTupleSchemeFactory());
}
@Override
public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
schemes.get(iprot.getScheme()).getScheme().read(iprot, this);
}
@Override
public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
schemes.get(oprot.getScheme()).getScheme().write(oprot, this);
}
public interface IScheme<T extends TBase> {
public void read(org.apache.thrift.protocol.TProtocol iproto, T struct) throws org.apache.thrift.TException;
public void write(org.apache.thrift.protocol.TProtocol oproto, T struct) throws org.apache.thrift.TException;
}
// IScheme 的两个抽象实现类
public abstract class StandardScheme<T extends TBase> implements IScheme<T> {}
public abstract class TupleScheme<T extends TBase> implements IScheme<T> {}
Thrift 生成的参数类把具体的编解码功能委托给了 XXXScheme 类
private static class sayHello_argsStandardSchemeFactory implements SchemeFactory {
@Override
public sayHello_argsStandardScheme getScheme() {
return new sayHello_argsStandardScheme();
}
}
private static class sayHello_argsStandardScheme extends StandardScheme<sayHello_args> {
@Override
public void read(org.apache.thrift.protocol.TProtocol iprot, sayHello_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: // USERNAME
if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
struct.username = iprot.readString();
struct.setUsernameIsSet(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();
struct.validate();
}
@Override
public void write(org.apache.thrift.protocol.TProtocol oprot, sayHello_args struct) throws org.apache.thrift.TException {
struct.validate();
oprot.writeStructBegin(STRUCT_DESC);
if (struct.username != null) {
oprot.writeFieldBegin(USERNAME_FIELD_DESC);
oprot.writeString(struct.username);
oprot.writeFieldEnd();
}
oprot.writeFieldStop();
oprot.writeStructEnd();
}
}
_Fields 为参数 id 和参数名称的便捷查找类。
// thrift 中每一个参数都有唯一的序号
public interface TFieldIdEnum {
public short getThriftFieldId();
public String getFieldName();
}
public enum _Fields implements org.apache.thrift.TFieldIdEnum {
USERNAME((short) 1, "username");
private static final Map<String, _Fields> byName = new HashMap<>();
static {
for (_Fields field : EnumSet.allOf(_Fields.class)) {
byName.put(field.getFieldName(), field);
}
}
public static _Fields findByThriftId(int fieldId) {
switch (fieldId) {
case 1: // USERNAME
return USERNAME;
default:
return null;
}
}
public static _Fields findByThriftIdOrThrow(int fieldId) {
_Fields fields = findByThriftId(fieldId);
if (fields == null) {
throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!");
}
return fields;
}
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;
}
@Override
public short getThriftFieldId() {
return _thriftId;
}
@Override
public String getFieldName() {
return _fieldName;
}
}
EnumSet.allOf 的使用
import java.util.EnumSet;
/**
* @author liguanghui02
* @date 2019/10/11
*/
public enum Tenum {
RED("red", 1),
WHITE("white", 2),
BLACK("black", 3),
YELLOW("yellow", 4);
private String name;
private int id;
Tenum(String name, int id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public static void main(String[] args) {
EnumSet<Tenum> tenums = EnumSet.allOf(Tenum.class);
for (Tenum tenum : tenums) {
System.out.println(tenum.getName() + ":" + tenum.getId());
}
}
}
javap -v Tenum
这就是 EnumSet.allOf 为什么可以获得所有枚举原因。
sayHello_result
方法返回值的封装类。
与 sayHello_args 类似,不再赘述。
总结
sayHello_result 封装的返回参数的索引为0,名称为 success,因为返回值只能有一个呦。
sayHello_args 封装的请求参数的索引为1,2,3…
thrift 将其他语言中类的概念抽象为 struct
// 伪代码,thrift 不支持 struct 嵌套
struct A {
struct B {
struct C {
}
}
}
thrift 使用一个字节 00 标识 struct 的结束,对于上面的代码,结束标记为 00 00 00。
客户端仅仅使用了 IDL 生成文件中的 【Iface、Client、sayHello_args、sayHello_result】。
服务端使用 Processor、AsyncProcessor。
TField
public class TField {
public final String name;
public final byte type;
public final short id;
}
TField 标识一个参数,【参数名称:参数类型:序号】
namespace java com.meituan.service
service HelloService
{
string sayHello(1:string username)
}
对应:org.apache.thrift.protocol.TField(“username”, org.apache.thrift.protocol.TType.STRING, (short)1)
TStruct
public final class TStruct {
public final String name;
}
field 的集合。
上一篇: PHP中调用SVN命令更新网站方法
下一篇: YII中model层的一个小问题。。