protobuf与protoc-gen-go
什么是protobuf
Protobuf(Protocol Buffer)是google 的一种数据交换的格式,它独立于语言,独立于平台。google 提供了多种语言的实现:java、c#、c++、go 和 python,每一种实现都包含了相应语言的编译器以及库文件。由于它是一种二进制的格式,比使用 xml 进行数据交换快许多。可以把它用于分布式应用之间的数据通信或者异构环境下的数据交换。作为一种效率和兼容性都很优秀的二进制数据传输格式,可以用于诸如网络传输、配置文件、数据存储等诸多领域。(参考链接)
什么是protoc
protoc是protobuf文件(.proto)的编译器(参考链接),可以借助这个工具把 .proto 文件转译成各种编程语言对应的源码,包含数据类型定义、调用接口等。
https://static.studygolang.com/180325/41775c725a2745e2e785f22bbd96a08c.png
通过查看protoc的源码(参见github库)可以知道,protoc在设计上把protobuf和不同的语言解耦了,底层用c++来实现protobuf结构的存储,然后通过插件的形式来生成不同语言的源码。可以把protoc的编译过程分成简单的两个步骤(如上图所示):1)解析.proto文件,转译成protobuf的原生数据结构在内存中保存;2)把protobuf相关的数据结构传递给相应语言的编译插件,由插件负责根据接收到的protobuf原生结构渲染输出特定语言的模板。
源码中(参见github库)包含的插件有 csharp、java、js、objectivec、php、python、ruby等多种。
什么是protoc-gen-go
protoc-gen-go是protobuf编译插件系列中的Go版本。从上一小节知道原生的protoc并不包含Go版本的插件,不过可以在github上发现专门的代码库(参见github库)。
由于protoc-gen-go是Go写的,所以安装它变得很简单,只需要运行 go get -u github.com/golang/protobuf/protoc-gen-go
,便可以在$GOPATH/bin目录下发现这个工具。至此,就可以通过下面的命令来使用protoc-gen-go了。
protoc --go_out=output_directory input_directory/file.proto
其中"--go_out="表示生成Go文件,protoc会自动寻找PATH(系统执行路径)中的protoc-gen-go执行文件。
protoc-gen-go的源码
https://static.studygolang.com/180325/fcfa10f6aa545027a3904783f0fd6ab5.png
按照Go的代码风格,protoc-gen-go源码主要包含六个包(package):
- main包
- doc.go 主要是说明。
- link_grpc.go 显式引用protoc-gen-go/grpc包,触发grpc的init函数。
- main.go 代码不到50行,初始化generator,并调用generator相应的方法输出protobuf的Go语言文件。
- generator包
- generator.go 包含了大部分由protobuf原生结构到Go语言文件的渲染方法,其中
func (g *Generator) P(str ...interface{})
这个方法会把渲染输出到generator的output(generator匿名嵌套了bytes.Buffer,因此有Buffer的方法)。 - name_test.go 测试,主要包含generator中名称相关方法的测试。
- generator.go 包含了大部分由protobuf原生结构到Go语言文件的渲染方法,其中
- grpc包
- grpc.go 与generator相似,但是包含了很多生成grpc相关方法的方法,比如渲染转译protobuf中定义的rpc方法(在generator中不包含,其默认不转译service的定义)
- descriptor 包含protobuf的描述文件(.proto文件及其对应的Go编译文件),其中proto文件来自于proto库(参见这里)
- plugin 包含plugin的描述文件(.proto文件及其对应的Go编译文件),其中proto文件来自于proto库,参见这里
结语
从巴别塔的传说(参见这里)可以知道,欲要构建大系统,个体之间的沟通规范很重要。protobuf的出现,为不同系统之间的连接提供了一种语言规范,只要遵循了这个规范,各个系统之间就是解耦的,非常适合近年来流行的微服务架构。
如果吧protoc和protoc-gen-go看成两个微服务,可以发现这两个服务就是完全解耦的;两者完全负责不同的功能,可以分别编码、升级,串接这两个服务的就是proto规范。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。