golang proto import 到底怎么做? 为什么?

2,321 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

1 怎么做?

先给出一个目前 我认为 最好的解决方案, 这么做的原因后面会一个个说,

曾经, 有这么一份真诚的文章放在我面前, 我没有珍惜...
结果浪费了我一整天看google官方文档

如果你是新手, 希望你别只是看, 跟着做一遍秒懂

(1) 把项目要用的proto文件都放到一个目录下

这个demo项目的代码组织结构如下:

image.png

统一把proto文件放到proto文件夹下, 再在里面按各个微服务名称创建文件夹
里面放该微服务的所有proto文件, 以及生成的pb.go和_grpc.pb.go
比如现在项目业务有这样一个需求, group服务需要读取message服务, 获取群消息, 即:

group.proto需要import msg.proto里的一个结构

如何实现呢? 往下看

(2) go.mod

go mod init go_test会生成下面的go.mod文件

module go_test

go 1.18

然后创建远程库, 手动把module go_test修改为
module github.com/CPALyth/go_test(替换为你自己的远程库地址)

(3) msg.proto

这个proto文件是被调用的, 记得替换为你自己的远程库地址

syntax = "proto3";
package msg;
option go_package = "github.com/CPALyth/go_test/proto/msg";

message ChatMsg {
    int64 id=1;  // 消息id
    string groupId=2;  // 群id
    int64 senderId=3;  // 发送者uid
    int64 type=4;  // 消息类型 1文本, 2图片, 3视频, 4音频
    string content=5;  // 消息内容
    string uuid=6;  // 作用是去重
    int64 createTime=7;  // 创建时间
}

(4) group.proto

group.proto文件 来调用 msg.proto

syntax = "proto3";
package group;
option go_package = "github.com/CPALyth/go_test/proto/group";
import "proto/msg/msg.proto";  // 注意这里就不要加github...了

// 获取消息页面 群组信息列表
message MessageGroupInfoListRequest {
    int64 userId=1;
}
message MessageGroupInfo {
    string groupId=1; // 群组id 
    string aliasName=2; // 备注 
    string avatarUrl=3; // 头像
    msg.ChatMsg lastMsg=4; // 最后一条消息, 注意看这里导入了msg的ChatMsg
}
message MessageGroupInfoListResponse {
    repeated MessageGroupInfo list=1;
}

service GroupClient {
    rpc MessageGroupInfoList(MessageGroupInfoListRequest) returns(MessageGroupInfoListResponse);
}

(5) 生成pb.go和_grpc.pb.go(重点)

生成被调用方(msg.proto)的go stub代码

protoc ./proto/msg/msg.proto --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:.

再生成group.proto的go stub代码

protoc ./proto/group/group.proto --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:.

(6) push, go mod tidy

go文件一片飘红, 不要紧,
运行 go mod tidy
现在完全no problem~~~

image.png

2 为什么?

(1) 为什么不能直接两个包都设置ChatMsg这样的结构体?

  1. ChatMsg类型冲突, 若后面业务中需要同时用GroupRpc和MessageRpc, 将出现runtime panic

image.png

  1. 如果ChatMsg以后改的话, 要两个文件都改, 代码复用性很低
  2. 细心的你可能会发现, 我这两个包名都是proto, 当然会冲突了, 但我告诉你, 你改了包名照样冲突

image.png

(2) 为什么要加上github.com/CPALyth/go_test/?

如果你在msg.proto里只写option go_package = "app/msg/rpc/proto"; 就会有如下事情发生, 它根本不会生成带go module名的路径

image.png

(3) go_out=paths=source_relative:. 是什么意思?

一般我们都是写go_out=./就是把pb.go文件 生成在 当前目录

paths=source_relative:.就是把pb.go文件 生成在 proto文件同级目录

还有另一种写法:

protoc proto/group/group.proto --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative

(4) 为什么不用--go_out=plugins=grpc,paths=source_relative:.?

较新版本的protoc-gen-go已经不再支持plugins=grpc这种写法了, 现在要用--go-grpc_out

image.png