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 条评论
登录 后参与评论

相关文章

来自专栏安恒网络空间安全讲武堂

seacms修复历程总结

seacms修复历程总结 从6.45版本开始search.php就存在前台getshell的漏洞,到6.54官方对其进行修补,但修复方法是对用户输入的参数进行过...

66070
来自专栏小樱的经验随笔

堆和栈的区别

一、预备知识—程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量...

36990
来自专栏java一日一条

架构设计基础知识整理

From http://msdn.microsoft.com/en-us/library/ff647859.aspx

8620
来自专栏Kirito的技术分享

JAVA 拾遗--Future 模式与 Promise 模式

写这篇文章的动机,是缘起于微信闲聊群的一场讨论,粗略整理下,主要涉及了以下几个具体的问题: 同步,异步,阻塞,非阻塞的关联及区别。 JAVA 中有 callb...

3.1K100
来自专栏cmazxiaoma的架构师之路

【分布式架构之旅】Redis入门

27630
来自专栏LeoXu的博客

Flex笔记_验证用户输入

11920
来自专栏java一日一条

2015年Java开发岗位面试题归类

3. 说说你知道的几个Java集合类:list、set、queue、map实现类咯。。。

10710
来自专栏Java学习网

Java阻塞队列线程集控制的实现方法

Java阻塞队列线程集控制的实现方法 队列以一种先进先出的方式管理数据。如果你试图向一个已经满了的阻塞队列中添加一个元素,或是从一个空的阻塞队列中移除一个元素...

33880
来自专栏大内老A

一个通过JSONP跨域调用WCF REST服务的例子(以jQuery为例)

JSONP(JSON with Padding)可以看成是JSON的一种“使用模式”,用以解决“跨域访问”的问题,这篇简单的文章给出一个简单的例子用于模拟如何通...

21970
来自专栏犀利豆的技术空间

徒手撸框架--实现 RPC 远程调用

微服务已经是每个互联网开发者必须掌握的一项技术。而 RPC 框架,是构成微服务最重要的组成部分之一。趁最近有时间。又看了看 dubbo 的源码。dubbo 为了...

17720

扫码关注云+社区

领取腾讯云代金券