Transcript
Page 1: Google protocol buffers简析

1

A Brief View of A Brief View of A Brief View of A Brief View of A Brief View of A Brief View of A Brief View of A Brief View of Google Protocol BuffersGoogle Protocol BuffersGoogle Protocol BuffersGoogle Protocol BuffersGoogle Protocol BuffersGoogle Protocol BuffersGoogle Protocol BuffersGoogle Protocol Buffers

刘海波刘海波刘海波刘海波 [email protected]@[email protected]@corp.netease.com

Page 2: Google protocol buffers简析

2

内容大纲内容大纲内容大纲内容大纲内容大纲内容大纲内容大纲内容大纲

简介简介简介简介示例示例示例示例.proto.proto.proto.proto语法语法语法语法数据编码数据编码数据编码数据编码测试对比测试对比测试对比测试对比实际应用实际应用实际应用实际应用Q&AQ&AQ&AQ&A

Page 3: Google protocol buffers简析

3

简介简介GPB googleGPB googleGPB googleGPB google开源的一种用于序列化结构化数据的协议。开源的一种用于序列化结构化数据的协议。开源的一种用于序列化结构化数据的协议。开源的一种用于序列化结构化数据的协议。

language-neutral, platform-neutral, language-neutral, platform-neutral, language-neutral, platform-neutral, language-neutral, platform-neutral, extensible way of serializing structured extensible way of serializing structured extensible way of serializing structured extensible way of serializing structured datadatadatadata适用于数据存储、传输适用于数据存储、传输适用于数据存储、传输适用于数据存储、传输

使用使用使用使用IDLIDLIDLIDL语言描述数据格式能够,然会对描述的数据进行二语言描述数据格式能够,然会对描述的数据进行二语言描述数据格式能够,然会对描述的数据进行二语言描述数据格式能够,然会对描述的数据进行二进制编码。进制编码。进制编码。进制编码。PBPBPBPB类似类似类似类似XMLXMLXMLXML,但是更快(速度:,但是更快(速度:,但是更快(速度:,但是更快(速度:XML DOMXML DOMXML DOMXML DOM文档文档文档文档树)、更小(生成的二进制数据)、更简单(编码、树)、更小(生成的二进制数据)、更简单(编码、树)、更小(生成的二进制数据)、更简单(编码、树)、更小(生成的二进制数据)、更简单(编码、proto proto proto proto vs schemavs schemavs schemavs schema)。下图是官网的数据()。下图是官网的数据()。下图是官网的数据()。下图是官网的数据(XML DOMXML DOMXML DOMXML DOM访问):访问):访问):访问):

编码复杂度对比参考编码复杂度对比参考编码复杂度对比参考编码复杂度对比参考《《《《Coding in GPB vs XML.docCoding in GPB vs XML.docCoding in GPB vs XML.docCoding in GPB vs XML.doc》》》》

Page 4: Google protocol buffers简析

4

示例示例安装环境安装环境安装环境安装环境,参考《,参考《,参考《,参考《Linux Linux Linux Linux 下安装下安装下安装下安装Google Protocol Google Protocol Google Protocol Google Protocol Buffers.docBuffers.docBuffers.docBuffers.doc》》》》.proto.proto.proto.proto编写编写编写编写编译生成目标类:编译生成目标类:编译生成目标类:编译生成目标类:

命令行:命令行:命令行:命令行:protoc -I=$SRC_DIR protoc -I=$SRC_DIR protoc -I=$SRC_DIR protoc -I=$SRC_DIR ––––java_out=$DST_DIR java_out=$DST_DIR java_out=$DST_DIR java_out=$DST_DIR $SRC_DIR/addressbook.proto $SRC_DIR/addressbook.proto $SRC_DIR/addressbook.proto $SRC_DIR/addressbook.proto 注:注:注:注:-I-I-I-I指定指定指定指定.proto.proto.proto.proto文件所文件所文件所文件所在目录在目录在目录在目录 ––––java_outjava_outjava_outjava_out指定生成指定生成指定生成指定生成javajavajavajava文件所在的目录文件所在的目录文件所在的目录文件所在的目录eclipseeclipseeclipseeclipse::::protoclipseprotoclipseprotoclipseprotoclipse插件插件插件插件

代码:代码:代码:代码:pbdemo\test\addresspbdemo\test\addresspbdemo\test\addresspbdemo\test\address::::

ListPeople.javaListPeople.javaListPeople.javaListPeople.java、、、、 AddPerson.java AddPerson.java AddPerson.java AddPerson.javapbdemo\test\com\example\tutorial\AddressBookProtos.javapbdemo\test\com\example\tutorial\AddressBookProtos.javapbdemo\test\com\example\tutorial\AddressBookProtos.javapbdemo\test\com\example\tutorial\AddressBookProtos.javapbdemo\test\demo\proto\addressbook.protopbdemo\test\demo\proto\addressbook.protopbdemo\test\demo\proto\addressbook.protopbdemo\test\demo\proto\addressbook.proto

Page 5: Google protocol buffers简析

5

示例示例解析解析AddressBookProtos.javaAddressBookProtos.javaAddressBookProtos.javaAddressBookProtos.java

编译生成目标类:编译生成目标类:编译生成目标类:编译生成目标类:命令行:命令行:命令行:命令行:protoc -I=$SRC_DIR protoc -I=$SRC_DIR protoc -I=$SRC_DIR protoc -I=$SRC_DIR ––––java_out=$DST_DIR java_out=$DST_DIR java_out=$DST_DIR java_out=$DST_DIR $SRC_DIR/addressbook.proto $SRC_DIR/addressbook.proto $SRC_DIR/addressbook.proto $SRC_DIR/addressbook.proto 注:注:注:注:-I-I-I-I指定指定指定指定.proto.proto.proto.proto文件所在目录文件所在目录文件所在目录文件所在目录 ––––java_outjava_outjava_outjava_out指定生成指定生成指定生成指定生成javajavajavajava文件所在的目录文件所在的目录文件所在的目录文件所在的目录eclipseeclipseeclipseeclipse::::protoclipseprotoclipseprotoclipseprotoclipse插件插件插件插件

代码:代码:代码:代码:pbdemo\test\addresspbdemo\test\addresspbdemo\test\addresspbdemo\test\address::::

ListPeople.javaListPeople.javaListPeople.javaListPeople.java、、、、 AddPerson.java AddPerson.java AddPerson.java AddPerson.javapbdemo\test\com\example\tutorial\AddressBookProtos.javapbdemo\test\com\example\tutorial\AddressBookProtos.javapbdemo\test\com\example\tutorial\AddressBookProtos.javapbdemo\test\com\example\tutorial\AddressBookProtos.javapbdemo\test\demo\proto\addressbook.protopbdemo\test\demo\proto\addressbook.protopbdemo\test\demo\proto\addressbook.protopbdemo\test\demo\proto\addressbook.proto

javajavajavajava文件中的类结构:文件中的类结构:文件中的类结构:文件中的类结构:class class class class AddressBookProtos{AddressBookProtos{AddressBookProtos{AddressBookProtos{ class class class class Person{Person{Person{Person{ class class class class PhoneNumber{PhoneNumber{PhoneNumber{PhoneNumber{class class class class Builder{} }Builder{} }Builder{} }Builder{} } class class class class Builder{}Builder{}Builder{}Builder{} } } } } class class class class AddressBook{AddressBook{AddressBook{AddressBook{class class class class Builder{} }Builder{} }Builder{} }Builder{} }}}}}

Page 6: Google protocol buffers简析

6

示例示例序列化序列化////////反序列化分析反序列化分析

所有的实体类都没有所有的实体类都没有所有的实体类都没有所有的实体类都没有settersettersettersetter方法,只有方法,只有方法,只有方法,只有gettergettergettergetter方法,相应的方法,相应的方法,相应的方法,相应的builderbuilderbuilderbuilder类中有类中有类中有类中有settersettersettersetter方法方法方法方法

通过通过通过通过查看查看查看查看代码可以看到,以上三个类的成员变量都是代码可以看到,以上三个类的成员变量都是代码可以看到,以上三个类的成员变量都是代码可以看到,以上三个类的成员变量都是privateprivateprivateprivate类型的,类型的,类型的,类型的,而而而而且且且且只提供只提供只提供只提供gettergettergettergetter方法,而没有提供方法,而没有提供方法,而没有提供方法,而没有提供settersettersettersetter方法去为数据变量赋值。方法去为数据变量赋值。方法去为数据变量赋值。方法去为数据变量赋值。PBPBPBPB利用了内部类可以访问到外部类中私有成员变量的特性。对外部类的任利用了内部类可以访问到外部类中私有成员变量的特性。对外部类的任利用了内部类可以访问到外部类中私有成员变量的特性。对外部类的任利用了内部类可以访问到外部类中私有成员变量的特性。对外部类的任何赋值操作都需要通过何赋值操作都需要通过何赋值操作都需要通过何赋值操作都需要通过BuilderBuilderBuilderBuilder内部类来进行。内部类来进行。内部类来进行。内部类来进行。当当当当调用调用调用调用BuilderBuilderBuilderBuilder的的的的build()build()build()build()方法时,方法时,方法时,方法时,会在方法体内创建一个会在方法体内创建一个会在方法体内创建一个会在方法体内创建一个指向外部类的引用(名为指向外部类的引用(名为指向外部类的引用(名为指向外部类的引用(名为resultresultresultresult),当赋),当赋),当赋),当赋值完成,会把这个对象返回。值完成,会把这个对象返回。值完成,会把这个对象返回。值完成,会把这个对象返回。PBPBPBPB通过这样一种方式保证了数据安全性,一旦数据构建完毕,将无法再对通过这样一种方式保证了数据安全性,一旦数据构建完毕,将无法再对通过这样一种方式保证了数据安全性,一旦数据构建完毕,将无法再对通过这样一种方式保证了数据安全性,一旦数据构建完毕,将无法再对其进行修改。其进行修改。其进行修改。其进行修改。

Page 7: Google protocol buffers简析

7

示例示例序列化序列化////////反序列化分析反序列化分析

一句话就可以实现反序列化:一句话就可以实现反序列化:一句话就可以实现反序列化:一句话就可以实现反序列化:AddressBook addressBook = AddressBook addressBook = AddressBook addressBook = AddressBook addressBook = AddressBook.parseFrom(new FileInputStream(filePath);AddressBook.parseFrom(new FileInputStream(filePath);AddressBook.parseFrom(new FileInputStream(filePath);AddressBook.parseFrom(new FileInputStream(filePath);PBPBPBPB在在在在parseFromparseFromparseFromparseFrom后面做的事情:后面做的事情:后面做的事情:后面做的事情:

根据根据根据根据inputStreaminputStreaminputStreaminputStream或者或者或者或者bufferbufferbufferbuffer去构造一个去构造一个去构造一个去构造一个CodedInputStreamCodedInputStreamCodedInputStreamCodedInputStream;;;;然后使用生成代码中的然后使用生成代码中的然后使用生成代码中的然后使用生成代码中的mergeFrommergeFrommergeFrommergeFrom方法,去解析二进制数据:方法,去解析二进制数据:方法,去解析二进制数据:方法,去解析二进制数据:

- 首先调用首先调用首先调用首先调用CodedInputStreamCodedInputStreamCodedInputStreamCodedInputStream的的的的readTagreadTagreadTagreadTag,也就是从中取得,也就是从中取得,也就是从中取得,也就是从中取得keykeykeykey值值值值((((intintintint类型),然后根据类型),然后根据类型),然后根据类型),然后根据tagtagtagtag找到找到找到找到fieldfieldfieldfield

- 然后通过然后通过然后通过然后通过swtichswtichswtichswtich块来往对象中赋值(块来往对象中赋值(块来往对象中赋值(块来往对象中赋值(PBPBPBPB采用了采用了采用了采用了Base 128 Base 128 Base 128 Base 128 VarintsVarintsVarintsVarints的方式来编码这个数字)。的方式来编码这个数字)。的方式来编码这个数字)。的方式来编码这个数字)。

将数据解析完成后,会调用将数据解析完成后,会调用将数据解析完成后,会调用将数据解析完成后,会调用build()build()build()build()方法,将构建好的对象返回。方法,将构建好的对象返回。方法,将构建好的对象返回。方法,将构建好的对象返回。注:在这个过程中要通过注:在这个过程中要通过注:在这个过程中要通过注:在这个过程中要通过PBPBPBPB提供的提供的提供的提供的DescriptorDescriptorDescriptorDescriptor类还获取每个字段的类还获取每个字段的类还获取每个字段的类还获取每个字段的描述信息。描述信息。描述信息。描述信息。

Page 8: Google protocol buffers简析

8

.proto.proto.proto.proto.proto.proto.proto.proto文件语法文件语法http://code.google.com/apis/protocolbuffers/dohttp://code.google.com/apis/protocolbuffers/dohttp://code.google.com/apis/protocolbuffers/dohttp://code.google.com/apis/protocolbuffers/docs/proto.htmlcs/proto.htmlcs/proto.htmlcs/proto.htmljavajavajavajava类是编译器根据类是编译器根据类是编译器根据类是编译器根据protoprotoprotoproto文件生成的。作为一个文件生成的。作为一个文件生成的。作为一个文件生成的。作为一个IDLIDLIDLIDL语言,语言,语言,语言,protoprotoprotoproto有相应的语法。有相应的语法。有相应的语法。有相应的语法。1111、、、、packagepackagepackagepackage::::protoprotoprotoproto文件以一个文件以一个文件以一个文件以一个packagepackagepackagepackage声明开始。这个声明是声明开始。这个声明是声明开始。这个声明是声明开始。这个声明是为了防止不同项目之间的命名冲突。(为了防止不同项目之间的命名冲突。(为了防止不同项目之间的命名冲突。(为了防止不同项目之间的命名冲突。(protoprotoprotoproto文件的文件的文件的文件的importimportimportimport))))2222、、、、java_packagejava_packagejava_packagejava_package3333、、、、java_outer_classnamejava_outer_classnamejava_outer_classnamejava_outer_classname:定义所有:定义所有:定义所有:定义所有messagemessagemessagemessage类的容器类。类的容器类。类的容器类。类的容器类。4444、、、、messagemessagemessagemessage:一组类型字段的集合。同时被:一组类型字段的集合。同时被:一组类型字段的集合。同时被:一组类型字段的集合。同时被messagemessagemessagemessage修饰过的字修饰过的字修饰过的字修饰过的字段,也可以当做类型,用于段,也可以当做类型,用于段,也可以当做类型,用于段,也可以当做类型,用于Nested messageNested messageNested messageNested message声明中。声明中。声明中。声明中。

常用类型:常用类型:常用类型:常用类型:WireType.docWireType.docWireType.docWireType.doc字段修饰:字段修饰:字段修饰:字段修饰:requiredrequiredrequiredrequired、、、、optionaloptionaloptionaloptional、、、、repeatedrepeatedrepeatedrepeated

5555、、、、enumenumenumenumtagtagtagtagimport protoimport protoimport protoimport proto升级升级升级升级protoprotoprotoproto文件:文件:文件:文件:

对已存在的任何字段,不能更改其标识(对已存在的任何字段,不能更改其标识(对已存在的任何字段,不能更改其标识(对已存在的任何字段,不能更改其标识(tagtagtagtag)号。)号。)号。)号。不能添加或删除任何不能添加或删除任何不能添加或删除任何不能添加或删除任何requiredrequiredrequiredrequired的字段的字段的字段的字段optional/repeatedoptional/repeatedoptional/repeatedoptional/repeated修饰新字段,标示新的修饰新字段,标示新的修饰新字段,标示新的修饰新字段,标示新的tagtagtagtag

Page 9: Google protocol buffers简析

9

.proto .proto .proto .proto .proto .proto .proto .proto 数据编码数据编码EncodingEncodingEncodingEncodingEncodingEncodingEncodingEncodinghttp://code.google.com/apis/protocolbuffers/dohttp://code.google.com/apis/protocolbuffers/dohttp://code.google.com/apis/protocolbuffers/dohttp://code.google.com/apis/protocolbuffers/docs/encoding.htmlcs/encoding.htmlcs/encoding.htmlcs/encoding.htmlPBPBPBPB的序列化编码对的序列化编码对的序列化编码对的序列化编码对keykeykeykey采用采用采用采用128 varint128 varint128 varint128 varint方式,能够使序列化后的二进制数方式,能够使序列化后的二进制数方式,能够使序列化后的二进制数方式,能够使序列化后的二进制数据占用空间小。据占用空间小。据占用空间小。据占用空间小。Varint Varint Varint Varint 是一种紧凑的表示数字的方法。它用一个或多个是一种紧凑的表示数字的方法。它用一个或多个是一种紧凑的表示数字的方法。它用一个或多个是一种紧凑的表示数字的方法。它用一个或多个字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表示数字的字节数。(示数字的字节数。(示数字的字节数。(示数字的字节数。([1,15][16,255][1,15][16,255][1,15][16,255][1,15][16,255]))))

变长编码的整数,它可能包含多个变长编码的整数,它可能包含多个变长编码的整数,它可能包含多个变长编码的整数,它可能包含多个bytebytebytebyte,对于每个,对于每个,对于每个,对于每个bytebytebytebyte的的的的8888位,其中后位,其中后位,其中后位,其中后7777位表示位表示位表示位表示数值,最高的一位表示是否还有还有另一个数值,最高的一位表示是否还有还有另一个数值,最高的一位表示是否还有还有另一个数值,最高的一位表示是否还有还有另一个bytebytebytebyte,,,,0000表示没有,表示没有,表示没有,表示没有,1111表示有;表示有;表示有;表示有;越前面的越前面的越前面的越前面的bytebytebytebyte表示数值的低位,后面的表示数值的低位,后面的表示数值的低位,后面的表示数值的低位,后面的bytebytebytebyte表示数值的高位;表示数值的高位;表示数值的高位;表示数值的高位;对于对于对于对于valuevaluevaluevalue,也是同样采用,也是同样采用,也是同样采用,也是同样采用varintvarintvarintvarint编码编码编码编码keykeykeykey的数据含义:的数据含义:的数据含义:的数据含义:X YYYY ZZZX YYYY ZZZX YYYY ZZZX YYYY ZZZ

- XXXX表示是否还有后续的表示是否还有后续的表示是否还有后续的表示是否还有后续的bytebytebytebyte来编码数字别名;来编码数字别名;来编码数字别名;来编码数字别名;- YYYYYYYYYYYYYYYY用于编码别名,定义了超过用于编码别名,定义了超过用于编码别名,定义了超过用于编码别名,定义了超过16161616个属性,则需要用到额外的个属性,则需要用到额外的个属性,则需要用到额外的个属性,则需要用到额外的bytebytebytebyte,一般,一般,一般,一般tagtagtagtag应该为应该为应该为应该为

[0,15][0,15][0,15][0,15]););););- ZZZZZZZZZZZZ表示这个字段的表示这个字段的表示这个字段的表示这个字段的wireType.jpgwireType.jpgwireType.jpgwireType.jpg

示例:示例:示例:示例:required int32 a = 255; -> F8 0F 96 01required int32 a = 255; -> F8 0F 96 01required int32 a = 255; -> F8 0F 96 01required int32 a = 255; -> F8 0F 96 01- required int32 a = 15; -> 78 96 01required int32 a = 15; -> 78 96 01required int32 a = 15; -> 78 96 01required int32 a = 15; -> 78 96 01

96 0196 0196 0196 01代表的是代表的是代表的是代表的是valuevaluevaluevalue,二进制为:,二进制为:,二进制为:,二进制为:1001 0110 0000 00011001 0110 0000 00011001 0110 0000 00011001 0110 0000 0001→→→→ 001 0110 000 0001 001 0110 000 0001 001 0110 000 0001 001 0110 000 0001(去掉最高位)(去掉最高位)(去掉最高位)(去掉最高位)→→→→ 22 + 22 + 22 + 22 + 1111****2^7 = 1502^7 = 1502^7 = 1502^7 = 150

Page 10: Google protocol buffers简析

10

.proto .proto .proto .proto .proto .proto .proto .proto 数据编码数据编码EncodingEncodingEncodingEncodingEncodingEncodingEncodingEncodinghttp://code.google.com/apis/protocolbuffers/docs/encoding.hhttp://code.google.com/apis/protocolbuffers/docs/encoding.hhttp://code.google.com/apis/protocolbuffers/docs/encoding.hhttp://code.google.com/apis/protocolbuffers/docs/encoding.html#typestml#typestml#typestml#types对于负数,对于负数,对于负数,对于负数,PBPBPBPB的采用的采用的采用的采用ZigZagZigZagZigZagZigZag方式进行序列化编码,将负数编码成正数。比传统的编方式进行序列化编码,将负数编码成正数。比传统的编方式进行序列化编码,将负数编码成正数。比传统的编方式进行序列化编码,将负数编码成正数。比传统的编码方式节省很多空间。码方式节省很多空间。码方式节省很多空间。码方式节省很多空间。

对于对于对于对于int32int32int32int32::::(n << 1) ^ (n >> 31)(n << 1) ^ (n >> 31)(n << 1) ^ (n >> 31)(n << 1) ^ (n >> 31)sint32:(n << 1) ^ (n >> 63)sint32:(n << 1) ^ (n >> 63)sint32:(n << 1) ^ (n >> 63)sint32:(n << 1) ^ (n >> 63)

Page 11: Google protocol buffers简析

11

测试对比测试对比测试对比测试对比vs XMLvs XMLvs XMLvs XML

通过通过通过通过pbpbpbpb生成的序列化文件:生成的序列化文件:生成的序列化文件:生成的序列化文件:personvs.bpersonvs.bpersonvs.bpersonvs.bxmlxmlxmlxml文件文件文件文件person.xmlperson.xmlperson.xmlperson.xml16161616进制比对:进制比对:进制比对:进制比对:

Page 12: Google protocol buffers简析

12

测试对比测试对比测试对比测试对比vs Othersvs Othersvs Othersvs Others

代码测试:代码测试:代码测试:代码测试:/pbdemo/test/demo/serializers/BenchmarkRunner.java/pbdemo/test/demo/serializers/BenchmarkRunner.java/pbdemo/test/demo/serializers/BenchmarkRunner.java/pbdemo/test/demo/serializers/BenchmarkRunner.java序列化方式:序列化方式:序列化方式:序列化方式:

java custom java custom java custom java custom javajavajavajavajson(jackson) customjson(jackson) customjson(jackson) customjson(jackson) customjson(jackson) annotationjson(jackson) annotationjson(jackson) annotationjson(jackson) annotationjson(gson)json(gson)json(gson)json(gson)protobufprotobufprotobufprotobuf

关注:关注:关注:关注:timeCreatetimeCreatetimeCreatetimeCreate:创建对象所需时间:创建对象所需时间:创建对象所需时间:创建对象所需时间timeSerializeDifferentObjects:timeSerializeDifferentObjects:timeSerializeDifferentObjects:timeSerializeDifferentObjects:序列化不同对象使用的时间序列化不同对象使用的时间序列化不同对象使用的时间序列化不同对象使用的时间timeSerializeSameObjecttimeSerializeSameObjecttimeSerializeSameObjecttimeSerializeSameObject:序列化相同的对象使用的时间:序列化相同的对象使用的时间:序列化相同的对象使用的时间:序列化相同的对象使用的时间timeDeserializetimeDeserializetimeDeserializetimeDeserialize:反序列化不同对象:反序列化不同对象:反序列化不同对象:反序列化不同对象totalTimetotalTimetotalTimetotalTime::::timeSerializeDifferentObjects+timeDeserializetimeSerializeDifferentObjects+timeDeserializetimeSerializeDifferentObjects+timeDeserializetimeSerializeDifferentObjects+timeDeserializelengthlengthlengthlength:序列化一次生成的:序列化一次生成的:序列化一次生成的:序列化一次生成的bytebytebytebyte长度长度长度长度

结果对比结果对比结果对比结果对比compare vs protocol bufferscompare vs protocol bufferscompare vs protocol bufferscompare vs protocol buffers

Page 13: Google protocol buffers简析

13

实际应用实际应用restrestrestrest应用:设定消息头:应用:设定消息头:应用:设定消息头:应用:设定消息头:

Content-TypeContent-TypeContent-TypeContent-Type::::application/x-protobufapplication/x-protobufapplication/x-protobufapplication/x-protobuf将序列化的二进制内容经过将序列化的二进制内容经过将序列化的二进制内容经过将序列化的二进制内容经过httphttphttphttp协议发送。协议发送。协议发送。协议发送。测试工程:测试工程:测试工程:测试工程:pbrestdemopbrestdemopbrestdemopbrestdemohttp://www.slideshare.net/mokeefe/javaone-2009-http://www.slideshare.net/mokeefe/javaone-2009-http://www.slideshare.net/mokeefe/javaone-2009-http://www.slideshare.net/mokeefe/javaone-2009-ts5276-restful-protocol-buffersts5276-restful-protocol-buffersts5276-restful-protocol-buffersts5276-restful-protocol-buffers

下一步应用研究:将下一步应用研究:将下一步应用研究:将下一步应用研究:将pbpbpbpb序列化后的数据存入到序列化后的数据存入到序列化后的数据存入到序列化后的数据存入到memcachememcachememcachememcache中中中中使用使用使用使用xmemcachexmemcachexmemcachexmemcache,重写,重写,重写,重写net.rubyeye.xmemcached.transcoders.SerializingTranet.rubyeye.xmemcached.transcoders.SerializingTranet.rubyeye.xmemcached.transcoders.SerializingTranet.rubyeye.xmemcached.transcoders.SerializingTranscoder serialize(Object o)nscoder serialize(Object o)nscoder serialize(Object o)nscoder serialize(Object o)方法方法方法方法参考工程:参考工程:参考工程:参考工程:xmemxmemxmemxmem

Page 14: Google protocol buffers简析

14

Q&AQ&AQ&AQ&AQ&AQ&AQ&AQ&A


Recommended