thrift 一个有意思的特性:Class名称无关性
2015-12-05 14:03
381 查看
最近开发的一个项目,后端采用thrift框架来提供rpc服务(java语言实现),然后前端采用php语言来生成thrift client调用后台RPC服务。由于某些原因,上周我把thrift定义文件中一个struct名称修改了,当然也没多想,顺手就把java服务端重新编译部署,而php前端的部署未做任何变化,按常规理解,服务契约中的类名,从A改成B,服务的调用方理应同步更新部署,否则感觉应该会出错。
然而,美好的事情就这么发生了,一切运行正常,依旧丝丝顺滑!
再然后,我就开始思考人生,重新理解 thrift内部的序列化与反序列化机制,很快就想明白了,借用之前写过的博客rpc框架之 avro 学习 2 - 高效的序列化中的一张图:
![](http://images2015.cnblogs.com/blog/27612/201509/27612-20150923221931178-1570429947.jpg)
thrift内部存储二进制数据时,为了提高存储效率,每个field都分配了一个数字编号,所以在序列化及反序列化时,其实是只认数字编号,不管名称的,这也正是thrift IDL文件定义struct时,为什么强制要求每个成员都要指定一个在struct本身范围内不重复的数字序号
IDL生成的具体语言的源代码中,解析对象时,同样也只看序号,以c#生成的代码为例:
从上面的case语句可以很清楚的看出,代码内部只认数字序号,不关心名称。
结论:只要不改变struct内部的成员类型和数字编号,struct对应的类名可以放心大胆的修改。
然而,美好的事情就这么发生了,一切运行正常,依旧丝丝顺滑!
再然后,我就开始思考人生,重新理解 thrift内部的序列化与反序列化机制,很快就想明白了,借用之前写过的博客rpc框架之 avro 学习 2 - 高效的序列化中的一张图:
![](http://images2015.cnblogs.com/blog/27612/201509/27612-20150923221931178-1570429947.jpg)
thrift内部存储二进制数据时,为了提高存储效率,每个field都分配了一个数字编号,所以在序列化及反序列化时,其实是只认数字编号,不管名称的,这也正是thrift IDL文件定义struct时,为什么强制要求每个成员都要指定一个在struct本身范围内不重复的数字序号
struct PersonModel { 1: i16 age = 0, 2: string name, 3: bool sex, 4: double salary, 5: byte childrenCount }
IDL生成的具体语言的源代码中,解析对象时,同样也只看序号,以c#生成的代码为例:
public void Read (TProtocol iprot) { iprot.IncrementRecursionDepth(); try { TField field; iprot.ReadStructBegin(); while (true) { field = iprot.ReadFieldBegin(); if (field.Type == TType.Stop) { break; } switch (field.ID) { case 1: if (field.Type == TType.I16) { Age = iprot.ReadI16(); } else { TProtocolUtil.Skip(iprot, field.Type); } break; case 2: if (field.Type == TType.String) { Name = iprot.ReadString(); } else { TProtocolUtil.Skip(iprot, field.Type); } break; case 3: if (field.Type == TType.Bool) { Sex = iprot.ReadBool(); } else { TProtocolUtil.Skip(iprot, field.Type); } break; case 4: if (field.Type == TType.Double) { Salary = iprot.ReadDouble(); } else { TProtocolUtil.Skip(iprot, field.Type); } break; case 5: if (field.Type == TType.Byte) { ChildrenCount = iprot.ReadByte(); } else { TProtocolUtil.Skip(iprot, field.Type); } break; default: TProtocolUtil.Skip(iprot, field.Type); break; } iprot.ReadFieldEnd(); } iprot.ReadStructEnd(); } finally { iprot.DecrementRecursionDepth(); } }
从上面的case语句可以很清楚的看出,代码内部只认数字序号,不关心名称。
结论:只要不改变struct内部的成员类型和数字编号,struct对应的类名可以放心大胆的修改。
相关文章推荐