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();
    }

解碼過程

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章