文章出處
文章列表
最近開發的一個項目,后端采用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對應的類名可以放心大膽的修改。
文章列表
全站熱搜