Thrift 调用分析

在这里插入图片描述

Thrift 定义文件

model.thrift

namespace java com.meituan.model

struct Request {
        1: required i32 age;
        2: required string name;
}

struct Response {
        1: required i16 code;
        2: required string msg;
}

helloservice.thrift

namespace java com.meituan.service

include "model.thrift"

service HelloService {
        model.Response sayHello(1: model.Request req)
}

服务端实现

public class HelloServiceImpl implements HelloService.Iface {
    @Override
    public Response sayHello(Request req) throws TException {
        System.out.println(req);
        Response response = new Response();
        response.setMsg("hi");
        response.setCode((short) 255);
        return response;
    }
}

服务端

public class Server {

    public static void main(String[] args) {
        TProcessor tprocessor = new HelloService.Processor<HelloService.Iface>(new HelloServiceImpl());
        TServerSocket serverTransport = null;
        try {
            serverTransport = new TServerSocket(6666);
        } catch (TTransportException e) {
            e.printStackTrace();
        }
        TServer.Args tArgs = new TServer.Args(serverTransport);
        tArgs.processor(tprocessor);
        tArgs.protocolFactory(new TBinaryProtocol.Factory());
        TServer server = new TSimpleServer(tArgs);
        server.serve();
    }
}

客户端

public class Client {
    public static void main(String[] args) {
        TTransport transport = new TSocket("127.0.0.1", 6666, 1000);
        try {
            transport.open();
        } catch (TTransportException e) {
            e.printStackTrace();
        }
        TProtocol protocol = new TBinaryProtocol(transport);
        HelloService.Client client = new HelloService.Client(protocol);

        Request request = new Request();
        request.setAge(27);
        request.setName("lgh");
        try {
            Response response = client.sayHello(request);
            System.out.println(response);
        } catch (TException e) {
            e.printStackTrace();
        }
        transport.close();
    }
}

编码(序列化):将对象转换为字节流
解码(反序列化):编码的逆过程

编码过程

client.sayHello(request) --> com.meituan.service.HelloService.Client#sayHello
Client 由 Thrift 为我们生成。

public com.meituan.model.Response sayHello(com.meituan.model.Request req) throws org.apache.thrift.TException
    {
      send_sayHello(req);
      return recv_sayHello();
    }

send_sayHello(req) --> com.meituan.service.HelloService.Client#send_sayHello

public void send_sayHello(com.meituan.model.Request req) throws org.apache.thrift.TException
    {
      sayHello_args args = new sayHello_args();
      args.setReq(req);
      sendBase("sayHello", args);
    }

方法名_args 是对请求参数的封装
sendBase(“sayHello”, args) --> org.apache.thrift.TServiceClient#sendBase(java.lang.String, org.apache.thrift.TBase<?,?>)

TServiceClient: A TServiceClient is used to communicate with a TService implementation across protocols and transports.

protected void sendBase(String methodName, TBase<?,?> args) throws TException {
    sendBase(methodName, args, TMessageType.CALL);
  }
private void sendBase(String methodName, TBase<?,?> args, byte type) throws TException {
	// 编码 1:写入 Thrift 请求消息头
    oprot_.writeMessageBegin(new TMessage(methodName, type, ++seqid_));
    args.write(oprot_);
    oprot_.writeMessageEnd();
    oprot_.getTransport().flush();
  }

args.write(oprot_) --> com.meituan.service.HelloService.sayHello_args#write

public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
      schemes.get(oprot.getScheme()).getScheme().write(oprot, this);
    }

schemes 对应的类型

private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
    static {
      schemes.put(StandardScheme.class, new sayHello_argsStandardSchemeFactory());
      schemes.put(TupleScheme.class, new sayHello_argsTupleSchemeFactory());
    }

TProtocol.getScheme() 默认返回

  public Class<? extends IScheme> getScheme() {
    return StandardScheme.class;
  }

所以 schemes.get(oprot.getScheme()).getScheme() 返回的 sayHello_argsStandardSchemeFactory

getScheme 方法返回的 sayHello_argsStandardScheme

private static class sayHello_argsStandardSchemeFactory implements SchemeFactory {
      public sayHello_argsStandardScheme getScheme() {
        return new sayHello_argsStandardScheme();
      }
    }

args.write(oprot_) 调用的是 com.meituan.service.HelloService.sayHello_args.sayHello_argsStandardScheme#write

public void write(org.apache.thrift.protocol.TProtocol oprot, sayHello_args struct) throws org.apache.thrift.TException {
		// 对请求参数(required 标识的引用类型的参数)进行非空检查
        struct.validate();
        // 编码 2:空
        oprot.writeStructBegin(STRUCT_DESC);
        if (struct.req != null) {
          //  编码 3:写入 1 字节的参数类型,2 字节的参数序列号
          oprot.writeFieldBegin(REQ_FIELD_DESC);
          // 
          struct.req.write(oprot);
          // 编码13:什么也不做
          oprot.writeFieldEnd();
        }
        // 编码 14:写入 1 字节的(00000000)
        oprot.writeFieldStop();
        // 编码 15:空
        oprot.writeStructEnd();
      }

struct.req.write(oprot) --> com.meituan.model.Request.RequestStandardScheme#write

    public void write(org.apache.thrift.protocol.TProtocol oprot, Request struct) throws org.apache.thrift.TException {
      struct.validate();
	  // 编码 4:空
      oprot.writeStructBegin(STRUCT_DESC);
      // 编码 5:写入 1 字节的参数类型,2 字节的参数序列号
      oprot.writeFieldBegin(AGE_FIELD_DESC);
      // 编码 6:写入 age
      oprot.writeI32(struct.age);
      // 编码 7:空
      oprot.writeFieldEnd();
      if (struct.name != null) {
        // 编码 8:写入 1 字节的参数类型,2 字节的参数序列号
        oprot.writeFieldBegin(NAME_FIELD_DESC);
        // 编码 9:写入 name
        oprot.writeString(struct.name);
        // 编码 10:空
        oprot.writeFieldEnd();
      }
      // 编码 11:写入 1 字节的(00000000)
      oprot.writeFieldStop();
      // 编码 12:空
      oprot.writeStructEnd();
    }

总结

编码的过程:

  • writeMessageBegin
    • writeStructBegin
      • writeFieldBegin
        • writeStructBegin
          • writeFieldBegin writeI32 writeFieldEnd
          • writeFieldBegin writeString writeFieldEnd
          • writeFieldEnd
          • writeFieldStop
        • writeStructEnd
      • writeFieldEnd
      • writeFieldStop
    • writeStructEnd
  • writeMessageEnd

连接编解码的处理器

TProcessor: 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;
}
public abstract class TBaseProcessor<I> implements TProcessor {
  // service 实现类
  private final I iface;
  // 方法名 - ProcessFunction 映射表
  private final Map<String,ProcessFunction<I, ? extends TBase>> processMap;

  protected TBaseProcessor(I iface, Map<String, ProcessFunction<I, ? extends TBase>> processFunctionMap) {
    this.iface = iface;
    this.processMap = processFunctionMap;
  }

  public Map<String,ProcessFunction<I, ? extends TBase>> getProcessMapView() {
    return Collections.unmodifiableMap(processMap);
  }

  @Override
  public boolean process(TProtocol in, TProtocol out) throws TException {
    TMessage msg = in.readMessageBegin();
    ProcessFunction fn = processMap.get(msg.name);
    if (fn == null) {
      TProtocolUtil.skip(in, TType.STRUCT);
      in.readMessageEnd();
      TApplicationException x = new TApplicationException(TApplicationException.UNKNOWN_METHOD, "Invalid method name: '"+msg.name+"'");
      out.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));
      x.write(out);
      out.writeMessageEnd();
      out.getTransport().flush();
      return true;
    }
    // 由 Thrift 生成的 ProcessFunction 负责真正调用(解析请求、发起调用、编码响应)
    fn.process(msg.seqid, in, out, iface);
    return true;
  }
}

TMessage
在这里插入图片描述

TProcessor tprocessor = new HelloService.Processor<HelloService.Iface>(new HelloServiceImpl());
在这里插入图片描述

解码过程

public abstract class ProcessFunction<I, T extends TBase> {
  private final String methodName;

  private static final Logger LOGGER = LoggerFactory.getLogger(ProcessFunction.class.getName());

  public ProcessFunction(String methodName) {
    this.methodName = methodName;
  }

  public final void process(int seqid, TProtocol iprot, TProtocol oprot, I iface) throws TException {
    T args = getEmptyArgsInstance();
    try {
      // 解码过程
      args.read(iprot);
    } catch (TProtocolException e) {
      iprot.readMessageEnd();
      TApplicationException x = new TApplicationException(TApplicationException.PROTOCOL_ERROR, e.getMessage());
      oprot.writeMessageBegin(new TMessage(getMethodName(), TMessageType.EXCEPTION, seqid));
      x.write(oprot);
      oprot.writeMessageEnd();
      oprot.getTransport().flush();
      return;
    }
    iprot.readMessageEnd();
    TBase result = null;

    try {
      result = getResult(iface, args);
    } catch(TException tex) {
      LOGGER.error("Internal error processing " + getMethodName(), tex);
      TApplicationException x = new TApplicationException(TApplicationException.INTERNAL_ERROR, 
        "Internal error processing " + getMethodName());
      oprot.writeMessageBegin(new TMessage(getMethodName(), TMessageType.EXCEPTION, seqid));
      x.write(oprot);
      oprot.writeMessageEnd();
      oprot.getTransport().flush();
      return;
    }

    if(!isOneway()) {
      oprot.writeMessageBegin(new TMessage(getMethodName(), TMessageType.REPLY, seqid));
      result.write(oprot);
      oprot.writeMessageEnd();
      oprot.getTransport().flush();
    }
  }

  // 单向调用,即不需要返回值
  protected abstract boolean isOneway();

  // 实际调用的方法
  public abstract TBase getResult(I iface, T args) throws TException;
  
  public abstract T getEmptyArgsInstance();

  public String getMethodName() {
    return methodName;
  }
}

解码过程
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

发布了778 篇原创文章 · 获赞 323 · 访问量 209万+

猜你喜欢

转载自blog.csdn.net/lgh1992314/article/details/105324690
今日推荐