google protocol buffer全解析------田纪原,2024年安卓开发进阶课程

本文详细探讨了Google Protocol Buffer(protobuf)的使用特性与编码原理。首先介绍了protobuf如何通过定义.proto文件生成定制的Java模型,强调了字段序号在编码解码过程中的关键作用。接着通过示例展示了protobuf的兼容性,如不同模型间转换、序号对编码大小的影响、对象类型向String的兼容性以及protobuf与json的互换。文章还详细解析了protobuf的varint编码方式,说明了protobuf编码结果不包含字段名,仅保留序号、类型和数据值。最后,文章列举了protobuf编码的5个特性,并预告了后续将要讨论的protobuf编码原理的其他部分。
摘要由CSDN通过智能技术生成

1.protocol buffer需要定义.proto描述文件,然后通过google提供的编译器生成特定的模型文件,之后就可以作为正常的java对象使用了

2.不可以直接创建对象,需要通过Builder进行

3.只有Builder才可以进行set

4.可以通过对象的toByteArray()和parseFrom()方法进行编码和解码

5.模型文件很大(至少在java这里是如此),其中所有的代码都是定制的,这其实是它很大的缺点之一

接着我们将继续深入探究protobuf的编码原理。

主要分为两个部分

第一部分是之前留下的几个伏笔展示protobuf的使用特性

第二部分是分析protobuf的编码原理,解释特性背后的原因

第一部分,Protobuf使用特性

1.不同类型对象的转换

我们先定义如下一个.proto文件

syntax = “proto3”;

option java_package = “cn.tera.protobuf.model”;
option java_outer_classname = “DifferentModels”;

message Person {
string name = 1;
int32 id = 2;
string email = 3;
}

message Article {
string title = 1;
int32 wordsCount = 2;
string author = 3;
}

其中我们定义了2个模型,一个Person,一个Article,虽然他们的字段名字不相同,但是类型和编号都是一致的

接着我们生成.java文件,最终文件结构如下图

img

此时我们尝试做如下的一个转换

/**

  • 测试不同模型间的转换
  • @throws Exception
    */
    @Test
    public void parseDifferentModelsTest() throws Exception {
    //创建一个Person对象
    DifferentModels.Person person = DifferentModels.Person.newBuilder()
    .setName(“person name”)
    .setId(1)
    .setEmail(“tera@google.com”)
    .build();
    //对person编码
    byte[] personBytes = person.toByteArray();
    //将编码后的数据直接merge成Article对象
    DifferentModels.Article article = DifferentModels.Article.parseFrom(personBytes);
    System.out.println(“article’s title:” + article.getTitle());
    System.out.println(“article’s wordsCount:” + article.getWordsCount());
    System.out.println(“article’s author:” + article.getAuthor());
    }

输出结果如下

article’s title:person name
article’s wordsCount:1
article’s author:tera@google.com

可以看到,虽然jsonBytes是由person对象编码得到的,但是可以用于article对象的解码,不但不会报错,所有的数据内容都是完整保留的

这种兼容性的前提是模型中所定义的字段类型和序号都是一一对应相同的

在平时的编码中,我们经常会遇到从数据库中读取数据模型,然后将其转换成业务模型,而很多时候,这2种模型的内容其实是完全一致的,此时我们也许就可以使用protobuf的这种特性,就可以省去很多低效的赋值代码

2.protobuf序号的重要性

我们看到在定义.proto文件时,字段后面会跟着一个"= X",这里并不是指这个字段的值,而是表示这个字段的“序号”,和正确地编码与解码息息相关,在我看来是protocol buffer的灵魂

我们定义如下的.proto文件,这里注意,Model1和Model2的name和id的序号有不同

syntax = “proto3”;

option java_package = “cn.tera.protobuf.model”;
option java_outer_classname = “TagImportance”;

message Model1 {
string name = 1;
int32 id = 2;
string email = 3;
}

message Model2 {
string name = 2;
int32 id = 1;
string email = 3;
}

定义如下的测试方法

/**

  • 序号的重要性测试
  • @throws Exception
    */
    @Test
    public void tagImportanceTest() throws Exception {
    TagImportance.Model1 model1 = TagImportance.Model1.newBuilder()
    .setEmail(“model1@google.com”)
    .setId(1)
    .setName(“model1”)
    .build();
    TagImportance.Model2 model2 = TagImportance.Model2.parseFrom(model1.toByteArray());
    System.out.println(“model2 email:” + model2.getEmail());
    System.out.println(“model2 id:” + model2.getId());
    System.out.println(“model2 name:” + model2.getName());
    System.out.println(“-------model2 数据---------”);
    System.out.println(model2);
    }

输出结果如下

model2 email:model1@google.com
model2 id:0
model2 name:
-------model2 数据---------
email: “model1@google.com”
1: “model1”
2: 1

可以看到,虽然Model1和Model2定义的字段类型和名字都是相同的,然而name和id的序号颠倒了一下,导致最终model2在解析byte数组时,无法正确将数据解析到对应的字段上,所以输出的id为0,而name字段为null

不过即使字段无法一一对应,但在输出model2.toString()时,我们依然可以看到数据是被解析到了,只不过无法对应到具体字段,只能用1,2来表示其字段名

3.protobuf序号对编码结果大小的影响

protobuf的序号不仅影响编码、解码的正确性,一定程度上还会影响编码结果的字节数

我们在上面的.proto文件中增加一个Model3,其中Model3中定义的字段没有变化,但是序号更改为16,17,18

syntax = “proto3”;

option java_package = “cn.tera.protobuf.model”;
option java_outer_classname = “TagImportance”;

message Model1 {
string name = 1;
int32 id = 2;
string email = 3;
}

message Model2 {
string name = 2;
int32 id = 1;
string email = 3;
}

message

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值