Protobuf学习笔记
Protobuf學(xué)習(xí)筆記
Posted by iamxhuon 2012/05/22 Leave a comment (0)Go to commentsProtocol buffers是什么?
首先了解一下Protocol Buffers(簡(jiǎn)稱ProtoBuf)是什么?官網(wǎng)對(duì)它的定義如下:
Protocol buffers are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler.
上述定義描述了Protocol Buffers的全部?jī)?yōu)點(diǎn):語(yǔ)言無(wú)法,平臺(tái)無(wú)關(guān),可擴(kuò)展,用于序列化結(jié)構(gòu)化數(shù)據(jù)。在官方定義之外我認(rèn)為protobuf一種通用結(jié)構(gòu)化組織數(shù)據(jù)描述語(yǔ)言,擁有一整套的簡(jiǎn)單語(yǔ)法規(guī)則,內(nèi)置的類型系統(tǒng)等等。因此在學(xué)習(xí)過(guò)程中,可以把它當(dāng)作一門簡(jiǎn)單的語(yǔ)言來(lái)看待。Protocol Buffers定義了描述文件的結(jié)構(gòu),而描述文件結(jié)構(gòu)的語(yǔ)法檢查,類型檢查則需要protoc來(lái)處理,這時(shí)protoc就是一個(gè)編譯器,在編譯過(guò)程中不但檢查語(yǔ)法還負(fù)責(zé)生成指定格式的目標(biāo)文件。
Protocol Buffers為以.proto文件生成的各種對(duì)象(不限語(yǔ)言)的提供一致的序列化手段,保證數(shù)據(jù)最終持久化后的格式一致。而需要序列化的數(shù)據(jù),由用戶根據(jù).proto文件提供的類,創(chuàng)建相應(yīng)的對(duì)象。
Protobuf的描述文件 proto
在使用Protobuf時(shí),定義描述文件是最重要的事情。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文件結(jié)構(gòu)
從上面的代碼可以看出,proto文件的結(jié)構(gòu)非常簡(jiǎn)單。
package java_package 定義生成的java類的package名稱。
message定義一種類型,類型以Java中的一個(gè)class,book是類名,在生成Java代碼時(shí),就是使用這個(gè)類名。
接下來(lái)是該類型中包含的字段,字段包括 [限定符 類型 字段名稱 = tag [default = 默認(rèn)值]]
- protobuf支持的類型
protobuf支持的默認(rèn)類型如下.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
除此之外,還支持枚舉,自定義類型等。使用方式見(jiàn)上面代碼示例。更詳細(xì)的介紹見(jiàn)官方文檔
protobuf的自定義類型,支持對(duì)象組合方式,在CPP中使用較少,在Java中廣泛采用,但是目前我們需要序列化的對(duì)象是瘦模型,用不上這種特性。
- protobuf的限定符
- required 必填項(xiàng),如果該項(xiàng)不設(shè)值,在序列化時(shí)會(huì)拋出RuntimeException,推薦不使用該字段,該字段一旦使用,無(wú)法更改。不利于以來(lái)的擴(kuò)展
- optional 不存在時(shí)使用默認(rèn)值,默認(rèn)值可自定義。系統(tǒng)默認(rèn)值如下:int = 0,bool = false,string=”"
- repeated 類似于Java中的List,在實(shí)際生成Java類時(shí),也是生成一個(gè)List來(lái)表示
- tag說(shuō)明
tag 的主要作用是用來(lái)標(biāo)識(shí)每一個(gè)field,序列化時(shí)會(huì)使用tag,取值為數(shù)字。如上面的id = 1,其中的1,即為tag。
在protobuf序列化encode時(shí)標(biāo)識(shí)每一個(gè)field,0-15比16-少一個(gè)byte,優(yōu)化時(shí)可以使用到。
- default值
proto文件中定義的默認(rèn)值在處理版本兼容時(shí)非常有用,下面會(huì)做相關(guān)介紹。
- guide style
Protocol Buffers官方提供了一個(gè)Guide Style。其中介紹了一些定義proto的優(yōu)秀實(shí)踐。一句話總結(jié)就是名稱時(shí),message名稱以駝峰方式定義,字段名則需要以如author_name方式定義。字段名在生成Java代碼時(shí),會(huì)自動(dòng)轉(zhuǎn)換為符合Java風(fēng)格的命名方式。
如何在項(xiàng)目中組織proto文件,暫時(shí)能想到下面三種方式:
1、一個(gè)項(xiàng)目中所有的class都在一個(gè)*.proto中定義?
2、每個(gè)class作為單獨(dú)的文件?
3、按模塊劃分.proto文件
目前還沒(méi)有確認(rèn)哪種方式更佳。
Protobuf 生成的對(duì)象及序列化
Protobuf 生成的Java對(duì)象是immutable的,生成后無(wú)法修改,生成的Java對(duì)象以Builder方式構(gòu)建,在調(diào)用Builder時(shí)為field設(shè)值。
- 序列化方法
Java接口提供的序列化相關(guān)方法如下: 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.在處理序列化及反序列化對(duì)象時(shí),發(fā)現(xiàn)難于對(duì)序列化方法的抽象,因?yàn)樯鲜鰩讉€(gè)方法都不是public的。因此在序列化對(duì)象時(shí),需要針對(duì)每一個(gè)Java對(duì)象實(shí)現(xiàn)其特定的序列化類。
擴(kuò)展問(wèn)題
Protobuf提供了極佳的擴(kuò)展性,在擴(kuò)展時(shí),必須滿足下面的要求:
- 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).
在擴(kuò)展之后可以實(shí)現(xiàn)下面的世界通
舊的系統(tǒng)可以讀新的數(shù)據(jù),但是無(wú)法讀取到新添加的內(nèi)容
新的系統(tǒng)可以讀舊的數(shù)據(jù),讀不到的新加元素使用默認(rèn)值
缺點(diǎn):
Protobuf無(wú)疑是一個(gè)非常優(yōu)秀的結(jié)構(gòu)化數(shù)據(jù)序列化協(xié)議,現(xiàn)在我們來(lái)說(shuō)一說(shuō)在Java環(huán)境下,它的一些缺點(diǎn):
1、不支持大數(shù)據(jù)集的處理,少于1M
2、不支持Date,Map這些Java內(nèi)建的對(duì)象
更多詳細(xì)信息請(qǐng)參照官方文件https://developers.google.com/protocol-buffers/docs
總結(jié)
以上是生活随笔為你收集整理的Protobuf学习笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ubuntu+eclipse+svn
- 下一篇: 程序集版本号