这篇文章中的 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, }}
做了以下事件:
- 初始化并设置options
定义handler办法
- 顺次调用options.Handlers
初始化并返回plugin{}
- 初始化plugin.handler时,调用了第2步的handler办法,顺次调用了注册的handler,(注册插件时传入的
plugin.WithHandler()
,例子放在最初)
- 初始化plugin.handler时,调用了第2步的handler办法,顺次调用了注册的handler,(注册插件时传入的
最初是外层的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}
做了以下事件:
- 获取插件名称,判断是否已注册
- 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 } } //无关内容略... }}
做了以下事件:
- 获取插件列表,收集所有参数
- 顺次调用所有插件的
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信息
总结
- 本篇介绍的是 micro 的插件应用及外部流程,次要用于自定义网关。不要和 go-micro 插件搞混同了。
- micro/plugin/build下内容是对于build和load插件.so的,不太欠缺这里就不深入研究了。