这里主要和大家演示如何使用go-micro。
如果想先从更高的角度了解相关的工具集,可以查看博客https://micro.mu/blog/2016/03/20/micro.html。
编写服务
顶级的服务接口Service,是构建服务所需的主要组件。它把所有Go-Micror的基础包打包成单一组件接口。
type Service interface {Init(...Option)Options() OptionsClient() client.ClientServer() server.ServerRun() errorString() string}
1. 初始化
micro.NewService
import "github.com/micro/go-micro"service := micro.NewService()
初始化时,也可以传入相关选项
service := micro.NewService(micro.Name("greeter"),micro.Version("latest"),)
所有的可选参数参考:配置项
micro.Flags
import ("github.com/micro/cli""github.com/micro/go-micro")service := micro.NewService(micro.Flags(cli.StringFlag{Name: "environment",Usage: "The environment",},))
service.Initmicro.Action
service.Init(micro.Action(func(c *cli.Context) {env := c.StringFlag("environment")if len(env) > 0 {fmt.Println("Environment set to", env)}}),)
service.Init
2. 定义API
我们使用protobuf文件来定义服务的API接口。使用protobuf可以非常方便去严格定义API,提供服务端与客户端双边具体一致的类型。
下面是定义的示例
greeter.proto
syntax = "proto3";service Greeter {rpc Hello(HelloRequest) returns (HelloResponse) {}}message HelloRequest {string name = 1;}message HelloResponse {string greeting = 2;}
我们定义了一个服务叫做Greeter的处理器,它有一个接收HelloRequest并返回HelloResponse的Hello方法。
3. 生成API接口
我们需要下面这个工具来生成protobuf代码文件,它们负责生成定义的go代码实现。
go get github.com/golang/protobuf/{proto,protoc-gen-go}
go get github.com/micro/protoc-gen-micro
protoc --proto_path=$GOPATH/src:. --micro_out=. --go_out=. greeter.proto
生成的类现在可以引入handler中,在服务或客户端来创建请求了。
下面是部分生成的代码
type HelloRequest struct {Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`}type HelloResponse struct {Greeting string `protobuf:"bytes,2,opt,name=greeting" json:"greeting,omitempty"`}// Greeter service 客户端的APItype GreeterClient interface {Hello(ctx context.Context, in *HelloRequest, opts ...client.CallOption) (*HelloResponse, error)}type greeterClient struct {c client.ClientserviceName 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 *HelloRequest, opts ...client.CallOption) (*HelloResponse, error) {req := c.c.NewRequest(c.serviceName, "Greeter.Hello", in)out := new(HelloResponse)err := c.c.Call(ctx, req, out, opts...)if err != nil {return nil, err}return out, nil}// Greeter service 服务端type GreeterHandler interface {Hello(context.Context, *HelloRequest, *HelloResponse) error}func RegisterGreeterHandler(s server.Server, hdlr GreeterHandler) {s.Handle(s.NewHandler(&Greeter{hdlr}))}
4. 实现handler处理器
func(ctx context.Context, req interface{}, rsp interface{}) error
通过上面的内容,我们看到,Greeter interface的签名的看上去就是这样:
type GreeterHandler interface {Hello(context.Context, *HelloRequest, *HelloResponse) error}
Greeter处理器实现:
import proto "github.com/micro/examples/service/proto"type Greeter struct{}func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error {rsp.Greeting = "Hello " + req.Namereturn nil}
处理器会与服务一起被注册,就像http处理器一样。
service := micro.NewService(micro.Name("greeter"),)proto.RegisterGreeterHandler(service.Server(), new(Greeter))
5. 运行服务
server.Run
注册卸载
if err := service.Run(); err != nil {log.Fatal(err)}
6. 完整的服务代码
greeter.go
package mainimport ("log""github.com/micro/go-micro"proto "github.com/micro/examples/service/proto""golang.org/x/net/context")type Greeter struct{}func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error {rsp.Greeting = "Hello " + req.Namereturn nil}func main() {service := micro.NewService(micro.Name("greeter"),micro.Version("latest"),)service.Init()proto.RegisterGreeterHandler(service.Server(), new(Greeter))if err := service.Run(); err != nil {log.Fatal(err)}}
需要注意的是,要保证服务发现机制运行起来,这样服务才能注册,其它服务或客户端才能发现它。快速启动可参考。
编写客户端
客户端包用于查询服务,当创建服务时,也包含了一个客户端,这个客户端匹配服务所使用的初始化包。
查询上面的服务很简单:
// 创建greate客户端,这需要传入服务名与服务的客户端方法构建的客户端对象greeter := proto.NewGreeterClient("greeter", service.Client())// 在Greeter handler上请求调用Hello方法rsp, err := greeter.Hello(context.TODO(), &proto.HelloRequest{Name: "John",})if err != nil {fmt.Println(err)return}fmt.Println(rsp.Greeter)
proto.NewGreeterClient