Skip to main content

服务分组

概述

go-zero 采用 gRPC 进行服务间的通信,我们通过 proto 文件来定义服务的接口,但是在实际的开发中,我们可能会有多个服务,如果不对服务进行文件分组,那么 goctl 生成的代码将会是一个大的文件夹,这样会导致代码的可维护性变差,因此服务分组可以提高代码的可读性和可维护性。

服务分组

在 go-zero 中,我们通过在 proto 文件中以 service 为维度来进行文件分组,我们可以在 proto 文件中定义多个 service,每个 service 都会生成一个独立的文件夹,这样就可以将不同的服务进行分组,从而提高代码的可读性和可维护性。

除了 proto 文件中定义了 service 外,分组与否还需要在 goctl 中控制,生成带分组或者不带分组的代码取决于开发者,我们通过示例来演示一下。

不带分组

假设我们有一个 proto 文件,如下:

syntax = "proto3";

package user;

option go_package = "github.com/example/user";

message LoginReq{}
message LoginResp{}
message UserInfoReq{}
message UserInfoResp{}
message UserInfoUpdateReq{}
message UserInfoUpdateResp{}
message UserListReq{}
message UserListResp{}

message UserRoleListReq{}
message UserRoleListResp{}
message UserRoleUpdateReq{}
message UserRoleUpdateResp{}
message UserRoleInfoReq{}
message UserRoleInfoResp{}
message UserRoleAddReq{}
message UserRoleAddResp{}
message UserRoleDeleteReq{}
message UserRoleDeleteResp{}


message UserClassListReq{}
message UserClassListResp{}
message UserClassUpdateReq{}
message UserClassUpdateResp{}
message UserClassInfoReq{}
message UserClassInfoResp{}
message UserClassAddReq{}
message UserClassAddResp{}
message UserClassDeleteReq{}
message UserClassDeleteResp{}

service UserService{
rpc Login (LoginReq) returns (LoginResp);
rpc UserInfo (UserInfoReq) returns (UserInfoResp);
rpc UserInfoUpdate (UserInfoUpdateReq) returns (UserInfoUpdateResp);
rpc UserList (UserListReq) returns (UserListResp);

rpc UserRoleList (UserRoleListReq) returns (UserRoleListResp);
rpc UserRoleUpdate (UserRoleUpdateReq) returns (UserRoleUpdateResp);
rpc UserRoleInfo (UserRoleInfoReq) returns (UserRoleInfoResp);
rpc UserRoleAdd (UserRoleAddReq) returns (UserRoleAddResp);
rpc UserRoleDelete (UserRoleDeleteReq) returns (UserRoleDeleteResp);

rpc UserClassList (UserClassListReq) returns (UserClassListResp);
rpc UserClassUpdate (UserClassUpdateReq) returns (UserClassUpdateResp);
rpc UserClassInfo (UserClassInfoReq) returns (UserClassInfoResp);
rpc UserClassAdd (UserClassAddReq) returns (UserClassAddResp);
rpc UserClassDelete (UserClassDeleteReq) returns (UserClassDeleteResp);
}

我们来看一下不分组的情况下,goctl 生成的代码结构:

$ goctl rpc protoc user.proto --go_out=. --go-grpc_out=. --zrpc_out=.
$ tree
.
├── etc
│   └── user.yaml
├── github.com
│   └── example
│   └── user
│   ├── user.pb.go
│   └── user_grpc.pb.go
├── go.mod
├── internal
│   ├── config
│   │   └── config.go
│   ├── logic
│   │   ├── loginlogic.go
│   │   ├── userclassaddlogic.go
│   │   ├── userclassdeletelogic.go
│   │   ├── userclassinfologic.go
│   │   ├── userclasslistlogic.go
│   │   ├── userclassupdatelogic.go
│   │   ├── userinfologic.go
│   │   ├── userinfoupdatelogic.go
│   │   ├── userlistlogic.go
│   │   ├── userroleaddlogic.go
│   │   ├── userroledeletelogic.go
│   │   ├── userroleinfologic.go
│   │   ├── userrolelistlogic.go
│   │   └── userroleupdatelogic.go
│   ├── server
│   │   └── userserviceserver.go
│   └── svc
│   └── servicecontext.go
├── user.go
├── user.proto
└── userservice
└── userservice.go

10 directories, 24 files
温馨提示

在不进行分组的情况下,不支持在 proto 文件中定义多个 service,否则会报错。

带分组

首先,我们需要在 proto 文件中定义多个 service,如下:

syntax = "proto3";

package user;

option go_package = "github.com/example/user";

message LoginReq{}
message LoginResp{}
message UserInfoReq{}
message UserInfoResp{}
message UserInfoUpdateReq{}
message UserInfoUpdateResp{}
message UserListReq{}
message UserListResp{}
service UserService{
rpc Login (LoginReq) returns (LoginResp);
rpc UserInfo (UserInfoReq) returns (UserInfoResp);
rpc UserInfoUpdate (UserInfoUpdateReq) returns (UserInfoUpdateResp);
rpc UserList (UserListReq) returns (UserListResp);
}

message UserRoleListReq{}
message UserRoleListResp{}
message UserRoleUpdateReq{}
message UserRoleUpdateResp{}
message UserRoleInfoReq{}
message UserRoleInfoResp{}
message UserRoleAddReq{}
message UserRoleAddResp{}
message UserRoleDeleteReq{}
message UserRoleDeleteResp{}
service UserRoleService{
rpc UserRoleList (UserRoleListReq) returns (UserRoleListResp);
rpc UserRoleUpdate (UserRoleUpdateReq) returns (UserRoleUpdateResp);
rpc UserRoleInfo (UserRoleInfoReq) returns (UserRoleInfoResp);
rpc UserRoleAdd (UserRoleAddReq) returns (UserRoleAddResp);
rpc UserRoleDelete (UserRoleDeleteReq) returns (UserRoleDeleteResp);
}

message UserClassListReq{}
message UserClassListResp{}
message UserClassUpdateReq{}
message UserClassUpdateResp{}
message UserClassInfoReq{}
message UserClassInfoResp{}
message UserClassAddReq{}
message UserClassAddResp{}
message UserClassDeleteReq{}
message UserClassDeleteResp{}
service UserClassService{
rpc UserClassList (UserClassListReq) returns (UserClassListResp);
rpc UserClassUpdate (UserClassUpdateReq) returns (UserClassUpdateResp);
rpc UserClassInfo (UserClassInfoReq) returns (UserClassInfoResp);
rpc UserClassAdd (UserClassAddReq) returns (UserClassAddResp);
rpc UserClassDelete (UserClassDeleteReq) returns (UserClassDeleteResp);
}

我们来看一下带分组的情况下,goctl 生成的代码结构:

# 通过 -m 指定 goctl 生成分组的代码
$ goctl rpc protoc user.proto --go_out=. --go-grpc_out=. --zrpc_out=. -m
$ tree
.
├── client
│   ├── userclassservice
│   │   └── userclassservice.go
│   ├── userroleservice
│   │   └── userroleservice.go
│   └── userservice
│   └── userservice.go
├── etc
│   └── user.yaml
├── github.com
│   └── example
│   └── user
│   ├── user.pb.go
│   └── user_grpc.pb.go
├── go.mod
├── internal
│   ├── config
│   │   └── config.go
│   ├── logic
│   │   ├── userclassservice
│   │   │   ├── userclassaddlogic.go
│   │   │   ├── userclassdeletelogic.go
│   │   │   ├── userclassinfologic.go
│   │   │   ├── userclasslistlogic.go
│   │   │   └── userclassupdatelogic.go
│   │   ├── userroleservice
│   │   │   ├── userroleaddlogic.go
│   │   │   ├── userroledeletelogic.go
│   │   │   ├── userroleinfologic.go
│   │   │   ├── userrolelistlogic.go
│   │   │   └── userroleupdatelogic.go
│   │   └── userservice
│   │   ├── loginlogic.go
│   │   ├── userinfologic.go
│   │   ├── userinfoupdatelogic.go
│   │   └── userlistlogic.go
│   ├── server
│   │   ├── userclassservice
│   │   │   └── userclassserviceserver.go
│   │   ├── userroleservice
│   │   │   └── userroleserviceserver.go
│   │   └── userservice
│   │   └── userserviceserver.go
│   └── svc
│   └── servicecontext.go
├── user.go
└── user.proto

19 directories, 28 files

通过目录结构我们可以看出,logic、server、client 目录都会根据 service 进行分组。