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

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

官网README中有一些介绍

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

官网示例:

在我的项目目录创立plugin.go

package mainimport (    "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        }),    ))}

最初编译

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

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

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{}对象

再来看plugin.NewPlugin()

// NewPlugin makes it easy to create a new pluginfunc 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 pluginsfunc 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 linefunc 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 mainimport (    "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的,不太欠缺这里就不深入研究了。