distill-infra集成了go-micro框架,在项目启动过程中,可以配置和启动GRpc进行服务之间的通信。
distill-micro-grpc项目是一个简单的服务之间通过grpc进行通信的用例。
Protoc v3.11.4 下载
protoc-go-inject-tag v1.0.0
go get -u github.com/favadi/protoc-go-inject-tag v1.0.0
gitee.com/banyanhouse/distill-infra v0.0.16 编写文档时为v0.0.16版本,建议使用最新发布的版本 github.com/golang/protobuf v1.4.2 github.com/micro/go-micro/v2 v2.5.0 github.com/sirupsen/logrus v1.4.2 golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 google.golang.org/genproto v0.0.0-20200521103424-e9a78aa275b7 // indirect google.golang.org/grpc v1.29.1
创建商品模型
# micro_prod_server -> Services -> protos -> Models.proto
syntax = "proto3";
option go_package = ".;Services";
package Services;
// 商品模型 通过@inject_tag注解为返回体属性设置了tag,是为了修改符合接口定义的返回体重的json数据标签
message ProdModel {
// @inject_tag: json:"pid"
int32 ProdId = 1;
// @inject_tag: json:"pname"
string ProdName = 2;
}
创建商品服务
对外暴露的接口,是由iris/context的ReadJson来将获取到的数据存放于如下的请求体ProdsRequest中,所以通过@inject_tag设定了校验和json序列化标签。在后面我们用gen.bat批处理文件中,调用了提前安装好的protoc-go-inject-tag来对生成的pd文件中的标签进行了统一修改。
# micro_prod_server -> Services -> protos -> ProdService.proto
syntax="proto3";
option go_package = ".;Services";
package Services;
import "Models.proto";
message ProdsRequest {
// @inject_tag: validate:"required" json:"size"
int32 size = 1;
}
message ProdListResponse {
repeated ProdModel data = 1;
}
service ProdService {
rpc GetProdsList(ProdsRequest) returns (ProdListResponse);
}
创建proto编译批处理文件
# micro_prod_server -> gen.bat
cd Services/protos
protoc -I . --micro_out=../ --go_out=plugins=grpc:../ Models.proto
protoc --proto_path=. --proto_path=.. --micro_out=../ --go_out=plugins=grpc:../ ProdService.proto
protoc-go-inject-tag -input=../Models.pb.go
cd .. && cd ..
执行以上批处理文件,我们即可生成编译后的pd.go和pd.micro.go文件,目录结构如下
Services
-- protos
---- Models.proto
---- ProdService.proto
-- Models.pd.go
-- Models.pd.micro.go # 该文件其实没有用,可以把批处理protoc第一行的 --micro_out=../ 去除,不再生成这个文件,因为Models.proto文件中,没有service的配置。
-- ProdService.pd.go
-- ProdService.pd.micro.go
在ProdService.pd.micro.go文件中,生成了RegisterProdServiceHandler函数,作为注册服务到注册中心的句柄函数。该函数内部接口prodService中的函数GetProdsList(ctx context.Context, in *ProdsRequest, out *ProdListResponse) error,就需要我们来编写实现,来对接收到的请求ProdsRequest
进行处理,并通过ProdListResponse
进行返回。具体实现如下,先创建一个独立的包ServiceImpl
package ServiceImpl
import (
"context"
"fmt"
"gitee.com/banyanhouse/distill-micro-grpc/micro_prod_server/Services"
"strconv"
)
type ProdService struct {
}
func (p *ProdService) GetProdsList(ctx context.Context, request *Services.ProdsRequest,
response *Services.ProdListResponse) error {
fmt.Printf("receive request:%d\n", request.Size)
models := make([]*Services.ProdModel, 0)
// 模拟数据取数场景
var i int32
for i=0; i<request.Size;i++{
models = append(models, newProd(100+i, "prodName" + strconv.Itoa(100 + int(i))))
}
response.Data = models
return nil
}
// 测试方法
func newProd(id int32, pname string) *Services.ProdModel {
return &Services.ProdModel{
ProdId: id,
ProdName: pname,
}
}
通过micro_prod_server -> apis -> grpcapi -> ProdGrpc.go 来注册该grpc接口服务到注册中心:
package grpcapi
import (
"fmt"
"gitee.com/banyanhouse/distill-infra/apigrpc"
"gitee.com/banyanhouse/distill-infra/register"
"gitee.com/banyanhouse/distill-micro-grpc/micro_prod_server/ServiceImpl"
"gitee.com/banyanhouse/distill-micro-grpc/micro_prod_server/Services"
log "github.com/sirupsen/logrus"
)
func init() {
apigrpc.RegisterGRpcApi(new(GRpcApi))
}
type GRpcApi struct {
}
func (g *GRpcApi) Init(grpcName, grpcPort string) {
register.GRpcRegister(grpcName, grpcPort)
// 获取框架go-micro的micro.Service,其内包含注册中心信息
grpcService := register.GrpcService()
// 通过RegisterProdServiceHandler将服务实现方法注册到注册中心中
err := Services.RegisterProdServiceHandler(grpcService.Server(), new(ServiceImpl.ProdService))
if err != nil {
log.Errorf("GRpc Service impl failed:%s\n", err.Error())
}
// 打印查看中策中心的服务列表清单
services, err := register.RegistryCenter().ListServices()
if err != nil {
log.Errorf("get registry service list failed. %s", err.Error())
}
for i, service := range services {
fmt.Printf("%d -----> %s\n", i, service.Name)
}
}
应用框架中需要在app.go中调用服务的初始化
package distill_micro_http
import (
"fmt"
infra "gitee.com/banyanhouse/distill-infra"
"gitee.com/banyanhouse/distill-infra/apigrpc"
"gitee.com/banyanhouse/distill-infra/base"
"gitee.com/banyanhouse/distill-infra/hook"
"gitee.com/banyanhouse/distill-infra/log"
"gitee.com/banyanhouse/distill-infra/register"
"gitee.com/banyanhouse/distill-infra/validator"
_ "gitee.com/banyanhouse/distill-micro-grpc/micro_prod_server/apis/grpcapi" // 将注册grpc服务包在这里进行引入,注册服务。
)
func init() {
fmt.Println("start app...")
infra.Register(&base.TomlPropsStarter{})
infra.Register(&log.LoggerStarter{}) // 如果需要输出日志到文件中,则可以打开这里,去初始化文件日志
infra.Register(&validator.ValidatorStarter{})
infra.Register(®ister.Etcd3Starter{})
infra.Register(&apigrpc.GRpcApiStarter{}) // 启动distill-infra框架的GRpc启动器
infra.Register(&hook.HookStarter{})
fmt.Println("load end ...")
}
配置信息
[app]
name = "micro_prod_server"
port = 18186
protocol = "grpc" #grpc http https
time = "10s"
testing = false
...
将micro_prod_server -> Services -> protos下的proto文件复制到micro-gateway -> Services -> protos文件夹中,同时将gen.bat也复制到micro-gateway项目的根路径中,执行生成pd.go和pd.micro.go文件。
编写一个Web路由,调用注册中心的grpc微服务。
package web
import (
"context"
"gitee.com/banyanhouse/distill-infra/api"
"gitee.com/banyanhouse/distill-infra/validator"
"gitee.com/banyanhouse/distill-infra/web"
"gitee.com/banyanhouse/distill-micro-grpc/micro-gateway/Services"
irisContext "github.com/kataras/iris/context"
"github.com/micro/go-micro/v2"
log "github.com/sirupsen/logrus"
)
func init() {
api.SetupApi(new(ProdsHandler))
}
type ProdsHandler struct {
}
func (c *ProdsHandler) Init() {
}
func (c *ProdsHandler) Setup() {
// 路由注册
groupRouter := web.IrisMainParty().Party("/v1/micro/grpc")
groupRouter.Post("/prod", ProdHandler)
}
func ProdHandler(ctx irisContext.Context) {
var (
res web.Res
)
// 开启一个go-micro服务调用客户端
myService := micro.NewService(
micro.Name("prod.client"),
)
// 声明注册中心micro_prod_server服务
prodService := Services.NewProdService(
"micro_prod_server",
myService.Client(),
)
var prodsRequest Services.ProdsRequest
// 接收客户端请求,以json形式加载到请求体
err := ctx.ReadJSON(&prodsRequest)
// 验证请求体内容
validatorErr := validator.ValidateStruct(&prodsRequest)
if err != nil || validatorErr != nil {
errRes(err, validatorErr, &res)
ctx.JSON(&res)
return
}
// 调用微服务接口
prodsList, err := prodService.GetProdsList(context.Background(), &prodsRequest)
if err != nil {
errRes(err, nil, &res)
ctx.JSON(&res)
return
}
// 响应REST数据
res = web.Res{
Code: web.ResCodeOk,
Message: "商品列表",
Data: prodsList.GetData(),
}
ctx.JSON(&res)
}
// 错误异常处理
func errRes(err error, validatorErr error, res *web.Res) {
var paramErr error
if err != nil {
paramErr = err
}
if validatorErr != nil {
paramErr = validatorErr
}
log.Error(paramErr)
res.Code = web.ResCodeRequestParamsError
res.Message = "参数错误:" + paramErr.Error()
}
配置文件
[app]
name = "micro_gateway"
port = 18081
protocol = "http" #grpc http https
time = "10s"
testing = false
...
micro-gateway输出:
micro_prod_server输出:
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。