go micro wrapper 中间件

本篇不涉及中间件底层是如何运作的,如有兴趣请见[micro server]篇

在options.go中有如下定义

// WrapClient is a convenience method for wrapping a Client with
// some middleware component. A list of wrappers can be provided.
// Wrappers are applied in reverse order so the last is executed first.
func WrapClient(w ...client.Wrapper) Option {
    return func(o *Options) {
        // apply in reverse
        for i := len(w); i > 0; i-- {
            o.Client = w[i-1](o.Client)
        }
    }
}

// WrapCall is a convenience method for wrapping a Client CallFunc
func WrapCall(w ...client.CallWrapper) Option {
    return func(o *Options) {
        o.Client.Init(client.WrapCall(w...))
    }
}

// WrapHandler adds a handler Wrapper to a list of options passed into the server
func WrapHandler(w ...server.HandlerWrapper) Option {
    return func(o *Options) {
        var wrappers []server.Option

        for _, wrap := range w {
            wrappers = append(wrappers, server.WrapHandler(wrap))
        }

        // Init once
        o.Server.Init(wrappers...)
    }
}

// WrapSubscriber adds a subscriber Wrapper to a list of options passed into the server
func WrapSubscriber(w ...server.SubscriberWrapper) Option {
    return func(o *Options) {
        var wrappers []server.Option

        for _, wrap := range w {
            wrappers = append(wrappers, server.WrapSubscriber(wrap))
        }

        // Init once
        o.Server.Init(wrappers...)
    }
}

这些参数设置用于micro.NewService()参数

有以下几种类型

  1. WrapClient() 用于用一些中间件组件包装Client,包装器以相反的顺序应用,因此最后一个先执行。
  2. WrapCall() 用于方便包装Client CallFunc
  3. WrapHandler() 将一系列handler中间件传给server,并初始化
  4. WrapSubscriber() 将一系列subscriber中间件传给server,并初始化

在server/wrapper.go中,定义了wrapper

// HandlerFunc represents a single method of a handler. It's used primarily
// for the wrappers. What's handed to the actual method is the concrete
// request and response types.
type HandlerFunc func(ctx context.Context, req Request, rsp interface{}) error

// SubscriberFunc represents a single method of a subscriber. It's used primarily
// for the wrappers. What's handed to the actual method is the concrete
// publication message.
type SubscriberFunc func(ctx context.Context, msg Message) error

// HandlerWrapper wraps the HandlerFunc and returns the equivalent
type HandlerWrapper func(HandlerFunc) HandlerFunc

// SubscriberWrapper wraps the SubscriberFunc and returns the equivalent
type SubscriberWrapper func(SubscriberFunc) SubscriberFunc

// StreamWrapper wraps a Stream interface and returns the equivalent.
// Because streams exist for the lifetime of a method invocation this
// is a convenient way to wrap a Stream as its in use for trace, monitoring,
// metrics, etc.
type StreamWrapper func(Stream) Stream

服务端主要是

  1. HandlerWrapper() 用于handler处理器的中间件
  2. SubscriberWrapper() 用于订阅的中间件
  3. StreamWrapper() 用于流的中间件

在client/wrapper.go中,定义了client的中间件

// CallFunc represents the individual call func
type CallFunc func(ctx context.Context, node *registry.Node, req Request, rsp interface{}, opts CallOptions) error

// CallWrapper is a low level wrapper for the CallFunc
type CallWrapper func(CallFunc) CallFunc

// Wrapper wraps a client and returns a client
type Wrapper func(Client) Client

// StreamWrapper wraps a Stream and returns the equivalent
type StreamWrapper func(Stream) Stream

客户端主要是

  1. CallWrapper() client call中间件
  2. Wrapper() client中间件
  3. StreamWrapper() 流中间件

下面是一个client 中间件 Wrapper 的例子

type logWrapper struct {
    client.Client
}

func (l *logWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
    md, _ := metadata.FromContext(ctx)
    fmt.Printf("[Log Wrapper] ctx: %v service: %s method: %s\n", md, req.Service(), req.Endpoint())
    return l.Client.Call(ctx, req, rsp)
}

func NewLogWrapper(c client.Client) client.Client {
    return &logWrapper{c}
}

NewLogWrapper()实现了type Wrapper func(Client) Client

下面是一个 handler wrapper的例子

func NewLogWrapper(fn server.HandlerFunc) server.HandlerFunc {
    return func(ctx context.Context, req server.Request, rsp interface{}) error {
        log.Printf("[Log Wrapper] Before serving request method: %v", req.Endpoint())
        err := fn(ctx, req, rsp)
        log.Printf("[Log Wrapper] After serving request")
        return err
    }
}

NewLogWrapper()实现了type HandlerWrapper func(HandlerFunc) HandlerFunc

HandlerFunc定义是type HandlerFunc func(ctx context.Context, req Request, rsp interface{}) error

所以我们看到中间件都是函数里return的写法

具体实例可以参考官方plugins中的opentracing wrapper写法

https://github.com/micro/go-p...

这里包括

  1. client.Client定义
  2. NewClientWrapper
  3. NewCallWrapper
  4. NewHandlerWrapper
  5. NewSubscriberWrapper

如果你想要实现自己的中间件,这里的官方实现是个不错的参考

Service Wrapper

很多时候需要从处理程序内部访问服务。Service Wrapper就是方式之一。它将服务嵌入到ctx中,这样就可以在handler中使用它。

srv := micro.NewService(
    micro.Name("com.example.srv.foo"),
)

srv.Init(
    micro.WrapClient(service.NewClientWrapper(srv))
    micro.WrapHandler(service.NewHandlerWrapper(srv)),
)

在srv.Init()中添加wrapper

在handler中可以这样使用service

func (e *Example) Handler(ctx context.Context, req *example.Request, rsp *example.Response) error {
    service, ok := micro.FromContext(ctx)
    if !ok {
        return errors.InternalServerError("com.example.srv.foo", "Could not retrieve service")
    }

    // do something with the service
    fmt.Println("Got service", service)
    return nil
}

在client wrapper中也可以使用

type myWrapper struct {
    client.Client
}

func (m *myWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
    service, ok = micro.FromContext(ctx)
    if !ok {
        return errors.InternalServerError("com.example.srv.foo.mywrapper", "Could not retrieve service")
    }

    // do something with the service
    fmt.Println("Got service", service)

    // now do some call
    return c.Client.Call(ctx, req, rsp, opts...)
}

go micro 分析系列文章
go micro server 启动分析
go micro client
go micro broker
go micro cmd
go micro config
go micro store
go micro registry
go micro router
go micro runtime
go micro transport
go micro web
go micro registry 插件consul
go micro plugin
go micro jwt 网关鉴权
go micro 链路追踪
go micro 熔断与限流
go micro wrapper 中间件
go micro metrics 接入Prometheus、Grafana


舞林
1.5k 声望38 粉丝

漫步风雨中