go micro plugin

这篇文章中的 plugin 主要讲https://github.com/micro/micro 中的插件,主要用于自定义网关中如何加载插件。(如文章[micro auth jwt])git

go-micro中的插件请见https://github.com/micro/go-p...github

官方README中有一些介绍web

https://github.com/micro/micr...segmentfault

官方示例:app

在项目目录建立plugin.goui

package main

import (
    "log"
    "github.com/micro/cli/v2"
    "github.com/micro/micro/v2/plugin"
)

func init() {
    plugin.Register(plugin.NewPlugin(
        plugin.WithName("example"),
        plugin.WithFlag(cli.StringFlag{
            Name:   "example_flag",
            Usage:  "This is an example plugin flag",
            EnvVars: []string{"EXAMPLE_FLAG"},
            Value: "avalue",
        }),
        plugin.WithInit(func(ctx *cli.Context) error {
            log.Println("Got value for example_flag", ctx.String("example_flag"))
            return nil
        }),
    ))
}

最后编译url

`go build -o micro ./main.go ./plugin.go`插件

一步步看看是怎样注册的,在micro/plugin/manager.go中code

type manager struct {
    sync.Mutex
    plugins    []Plugin
    registered map[string]bool
}

var (
    // global plugin manager
    defaultManager = newManager()
)

func newManager() *manager {
    return &manager{
        registered: make(map[string]bool),
    }
}

plugin包有默认`defaultManager = newManager()`,是一个manager{}对象router

再来看plugin.NewPlugin()

// NewPlugin makes it easy to create a new plugin
func NewPlugin(opts ...Option) Plugin {
    return newPlugin(opts...)
}

func newPlugin(opts ...Option) Plugin {
    options := Options{
        Name: "default",
        Init: func(ctx *cli.Context) error { return nil },
    }

    for _, o := range opts {
        o(&options)
    }

    handler := func(hdlr http.Handler) http.Handler {
        for _, h := range options.Handlers {
            hdlr = h(hdlr)
        }
        return hdlr
    }

    return &plugin{
        opts:    options,
        handler: handler,
    }
}

作了如下事情:

  1. 初始化并设置options
  2. 定义handler方法

    1. 依次调用options.Handlers
  3. 初始化并返回plugin{}

    1. 初始化plugin.handler时,调用了第2步的handler方法,依次调用了注册的handler,(注册插件时传入的plugin.WithHandler(),例子放在最后)

最后是外层的plugin.Register()

// Register registers a global plugins
func Register(plugin Plugin) error {
    return defaultManager.Register(plugin)
}

func (m *manager) Register(plugin Plugin) error {
    m.Lock()
    defer m.Unlock()

    name := plugin.String()

    if m.registered[name] {
        return fmt.Errorf("Plugin with name %s already registered", name)
    }

    m.registered[name] = true
    m.plugins = append(m.plugins, plugin)
    return nil
}

作了如下事情:

  1. 获取插件名称,判断是否已注册
  2. manager.plugins中添加当前plugin

到这里插件的注册就完成了,那什么是被调用的,怎么生效的呢?

接下来看cmd.Init()

// Init initialised the command line
func Init(options ...micro.Option) {
    Setup(cmd.App(), options...)

    cmd.Init(
        cmd.Name(name),
        cmd.Description(description),
        cmd.Version(buildVersion()),
    )
}

func setup(app *ccli.App) {
    //无关内容略...

    plugins := plugin.Plugins()

    for _, p := range plugins {
        if flags := p.Flags(); len(flags) > 0 {
            app.Flags = append(app.Flags, flags...)
        }

        if cmds := p.Commands(); len(cmds) > 0 {
            app.Commands = append(app.Commands, cmds...)
        }
    }

    before := app.Before

    app.Before = func(ctx *ccli.Context) error {

        //无关内容略...
        for _, p := range plugins {
            if err := p.Init(ctx); err != nil {
                return err
            }
        }

        //无关内容略...
    }
}

作了如下事情:

  1. 获取插件列表,收集全部参数
  2. 依次调用全部插件的Init()方法

下面是一个有plugin.WithHandler()的插件例子

package main

import (
    "net/http"

    "myauth/lib/token"

    log "github.com/micro/go-micro/v2/logger"
    "github.com/micro/micro/v2/cmd"
    "github.com/micro/micro/v2/plugin"
)

func main() {
    tk := &token.Token{}
    tk.Init([]byte("key123456"))
    plugin.Register(plugin.NewPlugin(
        plugin.WithName("auth"),
        plugin.WithHandler(
            JWTAuthWrapper(tk),
        ),
    ))

    cmd.Init()
}

func JWTAuthWrapper(t *token.Token) plugin.Handler {
    return func(h http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            log.Info("===========", r.URL.Path)
            //不须要登陆的url地址 strings.HasPrefix(r.URL.Path, "/hello") ||
            if r.URL.Path == "/myauth/Myauth/GetJwt" ||
                r.URL.Path == "/myauth/Myauth/InspectJwt" {
                h.ServeHTTP(w, r)
                return
            }

            // tokenstr := r.Header.Get("Authorization")//如今不能够用Authorization,须要用Bearer
            tokenstr := r.Header.Get("Bearer")
            log.Info("tokenstr", tokenstr)
            userFromToken, e := t.Decode(tokenstr)
            log.Info("userFromToken", userFromToken)
            if e != nil {
                _, _ = w.Write([]byte("unauthorized"))
                return
            }

            // r.Header.Set("X-Example-Username", userFromToken.UserName)
            h.ServeHTTP(w, r)
            return
        })
    }
}

这个例子是一个自定义micro网关,拦截请求检查header中的jwt token信息

总结

  1. 本篇介绍的是 micro 的插件使用及内部流程,主要用于自定义网关。不要和 go-micro 插件搞混淆了。
  2. micro/plugin/build下内容是关于build和load插件.so的,不太完善这里就不深刻研究了。

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

相关文章
相关标签/搜索