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
- writeStructBegin
- writeFieldEnd
- writeFieldStop
- writeFieldBegin
- writeStructEnd
- writeStructBegin
- 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;
}
}
解码过程