欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

IDL 生成文件

程序员文章站 2022-06-17 12:14:28
...

IDL 生成文件在 thrift 栈中的位置。
IDL 生成文件
对于如下的 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

IDL 生成文件
这就是 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 的集合。

相关标签: thrift