Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Protobuf 扩展指南

Protobuf 扩展指南

原创
作者头像
王磊-字节跳动
修改于 2020-05-12 15:47:41
修改于 2020-05-12 15:47:41
10.3K0
举报
文章被收录于专栏:01ZOO01ZOO

本文并非 Protobuf 的基础、语法介绍,更加关注 Protobuf 的扩展用法以及实际案例基础

这部分可以参考官方文档,proto3的语法在这里只做简要的介绍和整理。

一个 基础Message 的定义如下

代码语言:txt
AI代码解释
复制
syntax = "proto3";
import  "other.proto";

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}
  1. 字段一般是以 [ "repeated" ] type fieldName "=" fieldNumber [ "[" fieldOptions "]" ] ";" 格式定义的
  2. 通过 protoc 即其插件,这个 proto 类型的文件会被生成特定语言的结构体,这种语言里面的类型和 proto 文件中的基础类型对应关系在这里,在其他类型的对应关系上,比如 enum、timestamp、duration ( timestamp, duration 为拓展类型)等,由于不同语言的实现方式不同,转换方式也有所不同,取决于 protoc 或插件的实现。
  3. protobuf (如无特别说明,下文中指 protobuf 3)的数据结构通过一个 repeated 关键字实现,同时 v3 也支持了 map 类型。
  4. protobuf 支持嵌套,不支持继承。支持 any,oneof 等特殊的结构,实际取值方式和特定语言有关。
  5. protobuf 的结构体支持转换为 json 而非二进制格式,对应关系在这里,这点值得注意,一般来说一般语言中的结构体转换 json 有自己的转换库函数,但是如果使用 protobuf 的库来转换可能转换结构有所不同,本质原因是因为 protobuf 的库转换时的标准不同。
  6. option的定义格式是 "option" optionName "=" constant ";", 比如 option java_package = "com.example.foo"; options 有内置也有自定义的。这部分和高级部分关系比较大。
    1. options并不改变整个文件声明的含义,但却能够影响特定环境下处理方式。完整的内置选项可以在 google/protobuf/descriptor.proto 找到,不同的 option 和他所在的位置对应。
    2. option 有多种类型,比如 fileOption, fieldOption, methodOption 等等
    3. 当你需要自定义一些 option,方式是使用 proto2 的 extend 语法,下面给出了一个例子
代码语言:txt
AI代码解释
复制
import "google/protobuf/descriptor.proto";
extend google.protobuf.MessageOptions {
  optional string my_option = 51234;
}
message MyMessage {
  option (my_option) = "Hello world!";
}

// Java 中获取这个 option 
value = my_proto_file_pb2.MyMessage.DESCRIPTOR.GetOptions()
  .Extensions[my_proto_file_pb2.my_option]

另一个真实的例子,来自 google 的 http 扩展,这里插件会获取 名为 google.api.http 的 option,然后转换为 http 结构

代码语言:txt
AI代码解释
复制
extend google.protobuf.MethodOptions {
  // See `HttpRule`.
  HttpRule http = 72295728;
}


// 实际使用
service Messaging {
    rpc GetMessage(GetMessageRequest) returns (Message) {
        option (google.api.http) = {
                get:"/v1/messages/{message_id}"
            };
    }
}

扩展

protobuf 描述一切

本质上,protobuf 的能力是描述 entitymethod,基本上 entity、method 外加一些约定,就可以描述所有的协议了。事实上 google 的 api 定义 基本上都可以都可以找到 protobuf 的描述

这里 protobuf 的描述作用就可以是

  1. 一个可以被复用的类型 (或者是一种 WellKnownType)。
  2. 一个 rpc 服务的输入输出类型,或者 rpc 服务的 service 以及 method。
  3. 一个描述某种协议(基于 protobuf 扩展 )的元信息结构和扩展位置的约定。
  4. 其他各种内置或扩展的 proto 文件元信息 key value。

甚至,protobuf 能够描述 protobuf 自己。protoc 以及插件的解析 proto 文件原理中最重要的是一个 descriptor 结构,而这个结构也是 protobuf 描述的,这是一个鸡生蛋还是蛋生鸡的关系,事实上,最初的 descriptor 是开发 compile 的开发者手动写的,经过一段时间,再用 protoc 生成 descriptor 文件,用于 protoc 文件 (似乎是一种循环依赖)。

http 扩展

如上所述,google api 中定义了如何将 grpc 映射成 http 的协议,理解这套协议以及实现,是理解扩展 protobuf 的一个很好的出发点。

  1. 首先定义 映射协议以及描述对应关系的 entity, 这个 entity比较简单,文件 大部分实在描述映射的协议,以便于实际实现方参考这个描述来实现。
  2. 使用 protobuf 的 extend option 的方法来扩展协议,这之后就可以使用相关的关键字来定义 google.http.rule, 比如 option (google.api.http) = {get:"/v1/messages/{message_id}}
  3. 实现插件,使用相关的 descriptor 提取 proto 中的信息,转换为 httpRule 结构体,比如 grpc-ecosystem/grpc-gateway 里面的 protoc-gen-grpc-gateway 插件就利用这种方法提取出了 httpRule 结构,然后利用这种结构来实现来 grpc 方法对应的 http handler。比如这个函数 就是提取 httpRule 结构的方法。至此就实现了 结构、协议、proto 文件、生成文件直接的对应转换。
protobuf-http-extension
protobuf-http-extension

gogo 扩展

gogo-protobuf 是 protoc 的 go 语言插件的实现,在实现特定语言代码生成的基础了,实现了多种 扩展特性,原始的定义在 这里 , 有以下几类

  1. google.protobuf.EnumOptions/EnumValueOptions:Enum 选项,如 goproto_enum_prefix 表示 enum 前缀开关
  2. google.protobuf.FileOptions:全局/文件选项,如goproto_getters_all 是全局的打开是否生成 get 函数的开关,也有对应的 MessageOptions - goproto_gette
  3. google.protobuf.MessageOptions:类型选项,同上,只是作用范围不同
  4. oogle.protobuf.FieldOptions:字段选项,比较常用的有 nullable - 表示生成指针还是结构体,stdtime 表示转换 WellKnownType timestamp 为 time.Time 等

实际实现和一般的 protoc 的插件并无不同,descriptor 结构由 protoc 解析,插件从 descriptor 进一步的解析出 proto 文件结构,以及各种扩展的选项,然后生成go 语言的文件。

以 nullable 这个选项为例,生成语言文件的时候会使用 帮助函数 判断对应 field 是否设置了 Nullable 的 Extension,如果没设置或者设置为True,则生成的结构则带指针,默认值为 nil。

参考

  1. https://colobu.com/2019/10/03/protobuf-ultimate-tutorial-in-go/
  2. https://colobu.com/2015/01/07/Protobuf-language-guide/
  3. https://blog.csdn.net/xeseo/article/details/12832577

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
《你不知道的 WeakMap》番外篇
原文主要复习了“JavaScript垃圾回收机制”,“Map/WeakMap区别”和“WeakMap 属性和方法”。这很好弥补被我忽视的知识点。 另外,我们可以通过原文,以相同方式再去学 Set/WeakSet,效果会更好,本文后面也会介绍到。
pingan8787
2020/06/15
6130
【笔记】607- 读《你不知道的 WeakMap》笔记
原文主要复习了“JavaScript垃圾回收机制”,“Map/WeakMap区别”和“WeakMap 属性和方法”。这很好弥补被我忽视的知识点。 另外,我们可以通过原文,以相同方式再去学 Set/WeakSet,效果会更好,本文后面也会介绍到。 「总结开始,先看原文大纲:」
pingan8787
2020/06/02
4570
【基础复盘】ES6中 的 WeakMap 你会用了吗?
只有当我们手动设置 obj = null 的时候,才有可能回收 obj 所引用的对象。
coder_koala
2022/11/28
7590
干货 | WeakMap的特性及应用场景
“ 我们先从 WeakMap 的特性说起,然后聊聊 WeakMap 的一些应用场景。 ”     特性     1. WeakMap 只接受对象作为键名  const map = new WeakMap();map.set(1, 2);// TypeError: Invalid value used as weak map keymap.set(null, 2);// TypeError: Invalid value used as weak map key 2. WeakMap 的键名所引用的
腾讯NEXT学位
2019/07/15
1.3K0
干货 | WeakMap的特性及应用场景
Vue 3 高阶指南之 WeakMap
「WeakMap」 对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。
公众号---人生代码
2020/11/03
1.2K0
Vue 3 高阶指南之 WeakMap
ES6面试点-WeakMap与Map的区别
首先,WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。
用户10106350
2022/10/28
1.1K0
Map与WeakMap
Map对象用来保存键值对,并且能够记住键的原始插入顺序,任何对象或者原始值都可以作为键或者是值。 WeakMap对象同样用来保存键值对,对于键是弱引用的而且必须为一个对象,而值可以是任意的对象或者原始值。
WindRunnerMax
2020/08/27
5770
[科普]ES6一些不常见的小知识
写作不易,未经作者允许禁止以任何形式转载! WeakMap 前置知识[深入浅出]JavaScript GC 垃圾回收机制 什么是WeakMap? WeakMap是key / value的组合,key只接受对象,不接受基本类型,value可以为任意类型。 方法 set(key, value) 在WeakMap中设置一组关联对象,返回WeakMap对象 get(key) 返回key的关联对象,不存在时返回undefined has(key) 根据是否有key关联对象,放回一个Boolean值 delete(k
前端LeBron
2021/12/08
3710
What's New in JavaScript
编者按:转载自 ThinkJS 专栏,作者是怡红公子,奇舞团一哥,360资深前端工程师。单身,帅,有钱,头发多...
苏南
2020/12/16
4900
What's New in JavaScript
29.精读《JS 中的内存管理》
How JavaScript works: memory management + how to handle 4 common memory leaks
黄子毅
2022/03/14
5850
29.精读《JS 中的内存管理》
Set、Map、WeakSet、WeakMap详细介绍
Set、Map、WeakSet和WeakMap是ES6引入的新的数据结构,它们在处理数据时具有不同的特性和用途。本文将详细介绍它们的用法、特性、区别、优缺点以及使用场景和注意事项,并给出相应的代码示例。
can4hou6joeng4
2023/11/17
2980
介绍下 Set、Map、WeakSet 和 WeakMap 的区别?
向 Set 加入值的时候,不会发生类型转换,所以5和"5"是两个不同的值。Set 内部判断两个值是否不同,使用的算法叫做“Same-value-zero equality”,它类似于精确相等运算符(===),主要的区别是NaN等于自身,而精确相等运算符认为NaN不等于自身。
Javanx
2019/11/04
2K0
介绍下 Set、Map、WeakSet 和 WeakMap 的区别?
weakSet与js内存回收
比较1、2例子可以发现,当引用类型key的值指向为空的时候,使用WeakMap的时候会立即释放内存 当使用Map的时候不会立即释放内存。
epoos
2022/06/06
1.4K0
前端测试题:关于WeakMap结构,下列说法错误的是?
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
舒克
2020/03/12
1.5K0
ES6-标准入门·数据类型与数据结构
ES6 新增了 Synmbol 数据类型和 Set、Map 两种数据据结构,以及衍生的 WeakSet 和 WeakMap。之前工作中基本未用过,惭愧之至,努力学习之。
数媒派
2022/12/01
6860
深入理解 ES6 新增的数据结构 Map 与 WeakMap
JavaScript 的对象(Object),本质上是键值对的集合(Hash结构),但传统上只能用字符串当作键,这给它带来很大的使用限制
Leophen
2022/05/07
6670
ES6入门之Set 和 Map
Set 函数可以接受一个数组(或具有 iterable 接口的其他数据结构)作为参数,用来初始化,如下:
执行上下文
2022/07/26
4340
浅析 Map 和 WeakMap 区别以及使用场景
希望这一篇文章能让你对 Map 有更好的理解,或者能够帮你理解 Map 和 WeakMap
小丞同学
2021/08/16
3K1
Set 和 Map 数据结构
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
小小杰啊
2022/12/21
7050
ES6集合引用类型Map与WeakMap |8月更文挑战
在ES6之前,在JavaScript中实现‘键’=>‘值’,也就是我们常说的键值对,是用Object来完成的。但这种实现方式在特殊场景下的有问题的,ES6又出了一个为Map的新集合类型,为这门语言带来正真的键值对存储机制。
大熊G
2022/11/14
3830
ES6集合引用类型Map与WeakMap |8月更文挑战
相关推荐
《你不知道的 WeakMap》番外篇
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档