手记

thrift 一个有意思的特性:Class名称无关性

最近开发的一个项目,后端采用thrift框架来提供rpc服务(java语言实现),然后前端采用php语言来生成thrift client调用后台RPC服务。由于某些原因,上周我把thrift定义文件中一个struct名称修改了,当然也没多想,顺手就把java服务端重新编译部署,而php前端的部署未做任何变化,按常规理解,服务契约中的类名,从A改成B,服务的调用方理应同步更新部署,否则感觉应该会出错。

然而,美好的事情就这么发生了,一切运行正常,依旧丝丝顺滑!

再然后,我就开始思考人生,重新理解 thrift内部的序列化与反序列化机制,很快就想明白了,借用之前写过的博客rpc框架之 avro 学习 2 - 高效的序列化中的一张图:

 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#生成的代码为例:

 1    public void Read (TProtocol iprot) 
 2     { 
 3       iprot.IncrementRecursionDepth(); 
 4       try 
 5       { 
 6         TField field; 
 7         iprot.ReadStructBegin(); 
 8         while (true) 
 9         {
 10           field = iprot.ReadFieldBegin();
 11           if (field.Type == TType.Stop) { 
 12             break;
 13           }
 14           switch (field.ID)
 15           {
 16             case 1:
 17               if (field.Type == TType.I16) {
 18
                  Age = iprot.ReadI16();
 19               } else { 
 20                 TProtocolUtil.Skip(iprot, field.Type);
 21               }
 22               break;
 23             case 2:
 24               if (field.Type == TType.String) {
 25                 Name = iprot.ReadString();
 26               } else { 
 27                 TProtocolUtil.Skip(iprot, field.Type);
 28               }
 29               break;
 30             case 3:
 31               if (field.Type == TType.Bool) {
 32                 Sex = iprot.ReadBool();
 33               } else { 
 34                 TProtocolUtil.Skip(iprot, field.Type);
 35               }
 36               break;
 37             case 4:
 38               if (field.Type == TType.Double) {
 39                 Salary = iprot.ReadDouble();
 40               } else { 
 41                 TProtocolUtil.Skip(iprot, field.Type);
 42               }
 43               break;
 44             case 5:
 45               if (field.Type == TType.Byte) {
 46                 ChildrenCount = iprot.ReadByte();
 47               } else { 
 48                 TProtocolUtil.Skip(iprot, field.Type);
 49               }
 50               break;
 51             default: 
 52               TProtocolUtil.Skip(iprot, field.Type);
 53               break;
 54           }
 55           iprot.ReadFieldEnd();
 56         }
 57         iprot.ReadStructEnd();
 58       }
 59       finally
 60       {
 61         iprot.DecrementRecursionDepth();
 62       }
 63     }

从上面的case语句可以很清楚的看出,代码内部只认数字序号,不关心名称。

 

结论:只要不改变struct内部的成员类型和数字编号,struct对应的类名可以放心大胆的修改。 

0人推荐
随时随地看视频
慕课网APP