编写服务

未匹配的标注
本文档最新版为 3.x,旧版本可能放弃维护,推荐阅读最新版!

编写服务

这是编写服务及其相关的内部内容的更详细的指南. 顶级 服务 接口是构建服务的主要组件. 它将 Go Micro 的所有基础包包装到一个便捷的接口中.

type Service interface {
    Init(...Option)
    Options() Options
    Client() client.Client
    Server() server.Server
    Run() error
    String() string
}

1. 初始化

像这样使用 micro.NewService 创建服务。

import "github.com/micro/go-micro/v2"

service := micro.NewService() 

选项可以在创建期间传入.

service := micro.NewService(
        micro.Name("greeter"),
        micro.Version("latest"),
)

所有可用的选项都可以 在这里 找到.

Go Micro 还提供一种使用 micro.Flags 设置命令行标志的方法.

import (
        "github.com/micro/cli"
        "github.com/micro/go-micro/v2"
)

service := micro.NewService(
        micro.Flags(
                cli.StringFlag{
                        Name:  "environment",
                        Usage: "The environment",
                },
        )
)

要分析标志请使用 service.Init``micro.Action 此外访问标志使用该选项.

service.Init(
        micro.Action(func(c *cli.Context) {
                env := c.StringFlag("environment")
                if len(env) > 0 {
                        fmt.Println("Environment set to", env)
                }
        }),
)

Go Micro 提供预定义的标志, 如果调用 service.Init 这些标志将设置和解析. 在此处查看 所有标志

2. 定义 API

我们使用原型文件来定义服务 API 接口. 这是一种非常方便的方法来严格定义 API 并为服务器和客户端提供具体类型.

下面是一个示例定义。

greeter.proto

syntax = "proto3";

service Greeter {
    rpc Hello(Request) returns (Response) {}
}

message Request {
    string name = 1;
}

message Response {
    string greeting = 2;
}

在这里我们定义一个服务处理程序称为 Greeter 与 Hello 的方法, 它采取参数请求类型并返回响应.

3. 生成 API 接口

您需要以下规则来生成原型代码

我们使用 protoc, protoc-gen-go, protoc-gen-micro 来生成此定义的具体实现.

go get github.com/golang/protobuf/{proto,protoc-gen-go}
go get github.com/micro/micro/v2/cmd/protoc-gen-micro@master
protoc --proto_path=$GOPATH/src:. --micro_out=. --go_out=. greeter.proto

现在在发出请求时, 可以在服务器或客户端的 handler 中导入和使用生成的类型.

下面是生成的代码的一部分.

type Request struct {
    Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
}

type Response struct {
    Greeting string `protobuf:"bytes,2,opt,name=greeting" json:"greeting,omitempty"`
}

// Client API for Greeter service

type GreeterClient interface {
    Hello(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
}

type greeterClient struct {
    c           client.Client
    serviceName string
}

func NewGreeterClient(serviceName string, c client.Client) GreeterClient {
    if c == nil {
        c = client.NewClient()
    }
    if len(serviceName) == 0 {
        serviceName = "greeter"
    }
    return &greeterClient{
        c:           c,
        serviceName: serviceName,
    }
}

func (c *greeterClient) Hello(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
    req := c.c.NewRequest(c.serviceName, "Greeter.Hello", in)
    out := new(Response)
    err := c.c.Call(ctx, req, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}

// Server API for Greeter service

type GreeterHandler interface {
    Hello(context.Context, *Request, *Response) error
}

func RegisterGreeterHandler(s server.Server, hdlr GreeterHandler) {
    s.Handle(s.NewHandler(&Greeter{hdlr}))
}

4. 实现处理程序

服务器需要注册 处理程序 以服务请求. 处理程序是一种公共类型, 具有符合签名 func(ctx context.Context, req interface{}, rsp interface{}) error 的公共方法.

如上所示, Greeter 接口的处理程序签名如下所示.

type GreeterHandler interface {
        Hello(context.Context, *Request, *Response) error
}

下面是 Greeter 处理程序的实现.

import proto "github.com/micro/examples/service/proto"

type Greeter struct{}

func (g *Greeter) Hello(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
    rsp.Greeting = "Hello " + req.Name
    return nil
}

处理程序在服务中注册, 就像 http.Handler 一样.

service := micro.NewService(
    micro.Name("greeter"),
)

pb.RegisterGreeterHandler(service.Server(), new(Greeter))

您还可以创建双向流式处理器, 但我们会将该处理程序留给另一天.

5. 运行服务

该服务可以通过调用 server.Run 来运行. 这将导致服务绑定到配置中的地址 (默认为找到的第一个 RFC1918 接口和一个随机端口), 并侦听请求.

这还将在启动时向注册表注册服务, 并在发出终止信号时注销.

if err := service.Run(); err != nil {
    log.Fatal(err)
}

6. 完整的服务

greeter.go

package main

import (
        "log"

        "github.com/micro/go-micro/v2"
        pb "github.com/micro/examples/service/proto"

        "golang.org/x/net/context"
)

type Greeter struct{}

func (g *Greeter) Hello(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
        rsp.Greeting = "Hello " + req.Name
        return nil
}

func main() {
        service := micro.NewService(
                micro.Name("greeter"),
        )

        service.Init()

        pb.RegisterGreeterHandler(service.Server(), new(Greeter))

        if err := service.Run(); err != nil {
                log.Fatal(err)
        }
}

注意服务发现机制需要运行, 以便服务可以注册以被客户端和其他服务发现. 一个快速开始 在这里.

编写客户端

客户端 包用于查询服务. 创建服务时, 将包含与服务器使用的初始包匹配的客户端.

查询上述服务非常简单.

// create the greeter client using the service name and client
greeter := pb.NewGreeterService("greeter", service.Client())

// request the Hello method on the Greeter handler
rsp, err := greeter.Hello(context.TODO(), &pb.Request{
    Name: "John",
})
if err != nil {
    fmt.Println(err)
    return
}

fmt.Println(rsp.Greeting)

pb.NewGreeterClient 获取用于发出请求的服务名称和客户端.

完整的例子可以在这里 go-micro/examples/service 中找到.


本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
taadis
讨论数量: 0
发起讨论 查看所有版本


暂无话题~