Protobuf学习笔记
Protobuf學習筆記
Posted by iamxhuon 2012/05/22 Leave a comment (0)Go to commentsProtocol buffers是什么?
首先了解一下Protocol Buffers(簡稱ProtoBuf)是什么?官網對它的定義如下:
Protocol buffers are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler.
上述定義描述了Protocol Buffers的全部優點:語言無法,平臺無關,可擴展,用于序列化結構化數據。在官方定義之外我認為protobuf一種通用結構化組織數據描述語言,擁有一整套的簡單語法規則,內置的類型系統等等。因此在學習過程中,可以把它當作一門簡單的語言來看待。Protocol Buffers定義了描述文件的結構,而描述文件結構的語法檢查,類型檢查則需要protoc來處理,這時protoc就是一個編譯器,在編譯過程中不但檢查語法還負責生成指定格式的目標文件。
 Protocol Buffers為以.proto文件生成的各種對象(不限語言)的提供一致的序列化手段,保證數據最終持久化后的格式一致。而需要序列化的數據,由用戶根據.proto文件提供的類,創建相應的對象。
Protobuf的描述文件 proto
在使用Protobuf時,定義描述文件是最重要的事情。Protobuf描述文件格式如下:
/*** Created by IntelliJ IDEA.* User: huxing(xing.hu@360hqb.com)* Date: 12-5-22* Time: 下午2:22*/ package org.colorfuldays.ssm.domain.protobuf;option java_package = "org.colorfuldays.ssm.domain.protobuf";message User{optional int64 id = 1;optional string name = 2;optional string password = 3; }message book{optional int64 id = 1;optional string name = 2;optional string isbn = 3;repeated User author = 4;optional int64 publish_date = 5; }- proto文件結構
從上面的代碼可以看出,proto文件的結構非常簡單。
package java_package 定義生成的java類的package名稱。
message定義一種類型,類型以Java中的一個class,book是類名,在生成Java代碼時,就是使用這個類名。
接下來是該類型中包含的字段,字段包括 [限定符 類型 字段名稱 = tag [default = 默認值]] 
- protobuf支持的類型
protobuf支持的默認類型如下.proto TypeNotesC++ TypeJava Type double ? double double float ? float float int32 Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. int32 int int64 Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. int64 long uint32 Uses variable-length encoding. uint32 int1 uint64 Uses variable-length encoding. uint64 long1 sint32 Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. int32 int sint64 Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. int64 long fixed32 Always four bytes. More efficient than uint32 if values are often greater than 228. uint32 int1 fixed64 Always eight bytes. More efficient than uint64 if values are often greater than 256. uint64 long1 sfixed32 Always four bytes. int32 int sfixed64 Always eight bytes. int64 long bool ? bool boolean string A string must always contain UTF-8 encoded or 7-bit ASCII text. string String bytes May contain any arbitrary sequence of bytes. string ByteString  
除此之外,還支持枚舉,自定義類型等。使用方式見上面代碼示例。更詳細的介紹見官方文檔
 protobuf的自定義類型,支持對象組合方式,在CPP中使用較少,在Java中廣泛采用,但是目前我們需要序列化的對象是瘦模型,用不上這種特性。
- protobuf的限定符
 
- required 必填項,如果該項不設值,在序列化時會拋出RuntimeException,推薦不使用該字段,該字段一旦使用,無法更改。不利于以來的擴展
 - optional 不存在時使用默認值,默認值可自定義。系統默認值如下:int = 0,bool = false,string=”"
 - repeated 類似于Java中的List,在實際生成Java類時,也是生成一個List來表示
 
- tag說明
tag 的主要作用是用來標識每一個field,序列化時會使用tag,取值為數字。如上面的id = 1,其中的1,即為tag。
在protobuf序列化encode時標識每一個field,0-15比16-少一個byte,優化時可以使用到。 
- default值
proto文件中定義的默認值在處理版本兼容時非常有用,下面會做相關介紹。 
- guide style
Protocol Buffers官方提供了一個Guide Style。其中介紹了一些定義proto的優秀實踐。一句話總結就是名稱時,message名稱以駝峰方式定義,字段名則需要以如author_name方式定義。字段名在生成Java代碼時,會自動轉換為符合Java風格的命名方式。 
如何在項目中組織proto文件,暫時能想到下面三種方式:
 1、一個項目中所有的class都在一個*.proto中定義?
 2、每個class作為單獨的文件?
 3、按模塊劃分.proto文件
 目前還沒有確認哪種方式更佳。
Protobuf 生成的對象及序列化
Protobuf 生成的Java對象是immutable的,生成后無法修改,生成的Java對象以Builder方式構建,在調用Builder時為field設值。
- 序列化方法
Java接口提供的序列化相關方法如下: byte[] toByteArray();: serializes the message and returns a byte array containing its raw bytes. static Person parseFrom(byte[] data);: parses a message from the given byte array. void writeTo(OutputStream output);: serializes the message and writes it to an OutputStream. static Person parseFrom(InputStream input);: reads and parses a message from an InputStream.在處理序列化及反序列化對象時,發現難于對序列化方法的抽象,因為上述幾個方法都不是public的。因此在序列化對象時,需要針對每一個Java對象實現其特定的序列化類。
 
擴展問題
Protobuf提供了極佳的擴展性,在擴展時,必須滿足下面的要求:
- you must not change the tag numbers of any existing fields.
 - you must not add or delete any required fields.
 - you may delete optional or repeated fields.
 - you may add new optional or repeated fields but you must use fresh tag numbers (i.e. tag numbers that were never used in this protocol buffer, not even by deleted fields).
 
在擴展之后可以實現下面的世界通
 舊的系統可以讀新的數據,但是無法讀取到新添加的內容
 新的系統可以讀舊的數據,讀不到的新加元素使用默認值
缺點:
Protobuf無疑是一個非常優秀的結構化數據序列化協議,現在我們來說一說在Java環境下,它的一些缺點:
 1、不支持大數據集的處理,少于1M
 2、不支持Date,Map這些Java內建的對象
更多詳細信息請參照官方文件https://developers.google.com/protocol-buffers/docs
總結
以上是生活随笔為你收集整理的Protobuf学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: ubuntu+eclipse+svn
 - 下一篇: 程序集版本号