在网络通信和通用数据交换等应用场景中经常使用的技术是 JSON 或 XML,在微服务架构中通常使用另外一个数据交换的协议的工具ProtoBuf。,ProtoBuf也是我们做微服务开发,进行Go进阶实战中,必知必会的知道点。,今天就开始第一章内容:《一文带你玩转ProtoBuf》,你可能不知道ProtoBuf,但一定知道json或者xml,从一定意义上来说他们的作用是一样的。,ProtoBuf全称:protocol buffers,直译过来是:“协议缓冲区”,是一种与语言无关、与平台无关的可扩展机制,用于序列化结构化数据。,和json\xml最大的区别是:json\xml都是基于文本格式,ProtoBuf是二进制格式。,ProtoBuf相比于json\XML,更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。,我们只需要定义一次数据结构,就可以使用ProtoBuf生成源代码,轻松搞定在各种数据流和各种语言中写入、读取结构化数据。,建议大家使用主流版本v3,这是官网下载地址:https://github.com/protocolbuffers/ProtoBuf/releases,注意,不同的电脑系统安装包是不一样的:,(公众号无法跳转到外链,点击文末的阅读原文可以跳转到下载地址。),小技巧:Mac查看自己的芯片类型点击左上角的苹果图标,再点击关于本机,就可以查看了。,
,比如,我的处理器芯片是intel的,下载安装包之后是这样的:,
,bin目录下的protoc是ProtoBuf的工具集,下文会重点介绍它的使用。,注意:我们需要将下载得到的可执行文件protoc所在的 bin 目录加到我们电脑的环境变量中。,如果你的Mac安装了brew,安装ProtoBuf就更简单了,我们使用brew install ProtoBuf就可以了,
,这个protoc可以将proto文件编译为任何语言的文件,想要编译为go语言的,还需要下载另外一个可执行文件,命令是这样的:,下面就编写一个非常简单,但是五脏齐全的proto代码,我们再根据这段代码生成pb.go文件。,生成go代码,非常简单,使用下面的命令就可以了。,切换到.proto文件所在目录,指定proto源文件,自动生成代码。,执行上面的命令后,我们在项目中就自动生成了一个.pb.go的文件,
,入门ProtoBuf就是这么的简单:通过这几步我们就完成了ProtoBuf的下载、安装、编写了一个proto文件,并生成了能用Go语言读写ProtoBuf的源代码。,我们再深入了解一下probuf的用法:,下面再带大家深入了解一下ProtoBuf的知识点,避免在开发中踩坑。,小技巧:写proto和写go最大的区别是需要在结尾添加分号的;,在开发过程中给自己提个醒:如果是写proto需要加分号,如果是写go不需要加分号。,以我们上面的proto入门代码举例:,
,message:非常重要,用于定义消息结构体,不用着急,下文会重点讲解,细心的小伙伴一定注意到了 message 消息体中有一个 “repeated” 关键字,这在我们写Go的时候是没有的。,这是干什么用的呢?下面来详细解答一下:,关于数组类型,和Java、Go、PHP等语言中,定义数据类型不一样。,在ProtoBuf消息中定义数组类型,是通过在字段前面增加repeated关键词实现,标记当前字段是一个数组。,只要使用repeated标记类型定义,就表示数组类型。,我们来举两个例子:,下面定义的arrays表示int32类型的数组,下面定义的names表示字符串数组,repeated搞懂了,message又是干嘛用的呢?,消息(message),在ProtoBuf中指的就是我们要定义的数据结构。类似于Go中定义结构体。,message关键词用法也非常简单:,例子:,定义了一个Request消息,这个消息有3个字段,query是字符串类型,page和limit是int32类型。,ProtoBuf支持多种数据类型,例如:string、int32、double、float等等,我整理了一份ProtoBuf和go语言的数据类型映射表,细心的小伙伴可能又有疑问了,上面消息体中的 string query = 1; 这个1是什么呢?,这些数字是“分配表示号”:在消息定义中,每个字段后面都有一个唯一的数字,这个就是标识号。,这些标识号的作用是:用来在消息的二进制格式中识别各个字段的,一旦开始使用就不能够再改变。,注意:分配标识号在每个消息内唯一,不同的消息体是可以拥有相同的标识号的。,小技巧:[1,15]之内的标识号在编码的时候会占用一个字节。[16,2047]之内的标识号则占用2个字节。所以应该为那些频繁出现的消息元素保留 [1,15]之内的标识号。,小技巧:要为将来有可能添加的、频繁出现的字段预留一些标识号。,我们想保留一些标识号,留给以后用,可以使用下面语法:,如果使用了这些保留的标识号,protocol buffer编译器无法编译通过,将会输出警告信息。,
,编译器命令格式:,OPTION是命令的选项, PROTO_FILES是我们要编译的proto消息定义文件,支持多个。,常用的OPTION选项:,因为开篇我们就用Go举了例子,下面再用Java举个例子吧:,在当前目录导出java版本的代码,编译hello.proto消息,执行效果如下:,
,下载再带小伙伴们了解一下ProtoBuf的进阶知识点吧:枚举类型、消息嵌套和Map类型。,写Java的同学枚举一定用的很溜,但是写Go的同学可能有点懵了,Go是不直接支持枚举的,并没有Enum关键字。,关注我,后续会详解Go枚举相关的知识点,在这篇文章中不做重点介绍。,使用枚举的场景是这样的:,当定义一个消息类型的时候,可能想为一个字段指定“预定义值”中的其中一个值,这时候我们就可以通过枚举实现,比如这种:,运行效果如下:,
,在实际开发中,我们需要定义很多的proto,我们如何做到消息的复用呢?,答案就是:“消息嵌套”,我们在开发Java和PHP时,经常嵌套使用类,也可以使用其他类作为自己的成员属性类型;在开发Go时经常嵌套使用结构体。,在ProtoBuf中同样支持消息嵌套,可以在一个消息中嵌套另外一个消息,字段类型可以是另外一个消息类型。,我们来看下面3个经典示例:,类似类嵌套一样,消息也可以嵌套,比如这样:,我们在实际开发中,通常要定义很多消息,如果都写在一个proto文件,是不方便维护的。,小技巧:将消息定义写在不同的proto文件中,在需要的时候可以通过import导入其他proto文件定义的消息。,例子:,创建文件: article.proto,创建文件: list_article.proto,执行效果如下,我们顺利生成了.pb.go文件:,
,我们在Go语言开发中,最常用的就是切片类型和map类型了。,切片类型在ProtoBuf中对应的就是repeated类型,前面我们已经介绍过了。,再重点介绍一下map类型,ProtoBuf也是支持map类型的:,语法非常简单和通用,但是有几个问题需要我们注意:,我们举个典型的例子:学生的学科和分数就适合用map定义:,运行效果如下: ,
,再强调一下:,注意:Map 字段是不能使用repeated关键字修饰。,
,至此我们已经掌握了ProtoBuf的所有知识点,是不是非常简单清晰呢?,下面我们在Go项目中实战应用一下ProtoBuf,从ProtoBuf中读取数据,并且转换为我们常用的结构体,我创建了一个demo目录,创建了名为study_info.proto的文件,使用命令生成pb.go文件:,编写go文件,读取ProtoBuf中定义的字段,进行赋值,取值,转成结构体等操作:,proto编码和解码的操作和json是非常像的,都使用“Marshal”和“Unmarshal”关键字。,运行结果如下:,
,ProtoBuf作为开发微服务必选的数据交换协议,基于二进制传输,比json/xml更小,速度更快,使用也非常的简单。,通过这篇文章,我们不仅学会了ProtoBuf的入门操作,还使用Go语言基于ProtoBuf编码解码了数据,进行了实战。,进阶部分带大家了解了ProtoBuf如何定义消息、ProtoBuf和Go数据类型的映射、枚举类型如何使用、通过消息嵌套复用代码、使用map类型时需要注意的问题和小技巧。,本文转载自微信公众号「 程序员升级打怪之旅」,作者「王中阳Go」,可以通过以下二维码关注。,
,转载本文请联系「 程序员升级打怪之旅」公众号。
© 版权声明
文章版权归作者所有,未经允许请勿转载。