thrift 一个有意思的特性:Class名称无关性
时间:2022-04-22
本文章向大家介绍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对应的类名可以放心大胆的修改。
- 祭奠那些年,我弃坑的开源轮子
- 这些奇技浮巧,助你优化前端应用性能
- Stepping.js——两步完成前后端分离架构设计
- 我的职业是前端工程师【十】客户端存储艺术:数据存储与模型
- 【开源】2md:将复制的内容、网页转成 markdown
- React Native 持续部署实践— push 代码构建出新版的 Growth
- 技巧 - 如何好一个 Git 提交信息及几种不同的规范
- React、Vue、Ember 及其他前端开发者,请暂缓更新到 Chrome 59 浏览器
- 微软开源全新的文档生成工具DocFX
- 使用 MimeKit 和 MailKit 发送邮件
- 使用 React Native 重写大型 Ionic 应用后,我们想分享一下这八个经验
- 基于OWin的Web服务器Katana发布版本3
- 【工具推荐】图像界的魔术师 ImageMagick
- 使用Metrics.NET 构建 ASP.NET MVC 应用程序的性能指标
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android APP存活检测方式
- 利用Android两行代码真正杀死你的App
- android判断应用是否已经启动的实例
- 解决android studio引用远程仓库下载慢(JCenter下载慢)
- 在Android中查看当前Activity是否销毁的操作
- Android 7.0 运行时权限弹窗问题的解决
- Android加密之全盘加密详解
- Android 实现彻底退出自己APP 并杀掉所有相关的进程
- 使用Android开发接入第三方原生SDK实现微信登录
- Android打包篇:Android Studio将代码打包成jar包教程
- Android系统制作自定义签名的例子
- 抖音短视频系统开发,日期加减
- Android开发之InetAddress基础入门简介与源码实例
- Android实现通讯录功能
- 教你用CentOS7下使用mktorrent制作PT种子