注:本文的micro 版本为v3.0
1. 一切的开始
packagemain//go:generate./scripts/generate.shimport("fmt""os""github.com/micro/micro/v3/cmd"//internalpackages_"github.com/micro/micro/v3/internal/usage"//loadpackagessotheycanregistercommands_"github.com/micro/micro/v3/client/cli"_"github.com/micro/micro/v3/client/cli/init"_"github.com/micro/micro/v3/client/cli/new"_"github.com/micro/micro/v3/client/cli/signup"_"github.com/micro/micro/v3/client/cli/user"_"github.com/micro/micro/v3/server"_"github.com/micro/micro/v3/service/auth/cli"_"github.com/micro/micro/v3/service/cli"_"github.com/micro/micro/v3/service/config/cli"_"github.com/micro/micro/v3/service/network/cli"_"github.com/micro/micro/v3/service/runtime/cli"_"github.com/micro/micro/v3/service/store/cli")funcmain(){iferr:=cmd.DefaultCmd.Run();err!=nil{fmt.Println(err)os.Exit(1)}}
一眼看去,内容确实是不多的。主要涉及的操作就是执行默认命令行的Run方法,并进行错误检测。
但是从导入的软件包看去,可以发现其实内容还是不少的,只不是大多都是进行初始化操作。我们可以看看主要有哪些,以及它的主要用途是做什么的。
2.plugin
第一个匿名导入的是一个内部包usage
,我们来看他主要做了什么
funcinit(){plugin.Register(Plugin())}funcPlugin()plugin.Plugin{varrequestsuint64//createrandsource:=rand.NewSource(time.Now().UnixNano())r:=rand.New(source)returnplugin.NewPlugin(plugin.WithName("usage"),plugin.WithInit(func(c*cli.Context)error{//onlydoifenabledif!c.Bool("report_usage"){os.Setenv("MICRO_REPORT_USAGE","false")returnnil}varservicestring//setservicenameifc.Args().Len()>0&&len(c.Args().Get(0))>0{service=c.Args().Get(0)}//servicesubcommandifservice=="service"{//setasthesubcommandifv:=c.Args().Get(1);len(v)>0{service=v}}//kickoffthetrackergofunc(){//newreportu:=New(service)//initialpublishin30-60secondsd:=30+r.Intn(30)time.Sleep(time.Second*time.Duration(d))for{//getservicelists,_:=registry.ListServices()//getrequestsreqs:=atomic.LoadUint64(&requests)srvs:=uint64(len(s))//resetrequestsatomic.StoreUint64(&requests,0)//setmetricsu.Metrics.Count["instances"]=uint64(1)u.Metrics.Count["requests"]=reqsu.Metrics.Count["services"]=srvs//attempttosendreport3timesfori:=1;i<=3;i++{iferr:=Report(u);err!=nil{time.Sleep(backoff.Do(i*2))continue}break}//nowsleep24hourstime.Sleep(time.Hour*24)}}()returnnil}),plugin.WithHandler(func(hhttp.Handler)http.Handler{//onlyenableifsetifv:=os.Getenv("MICRO_REPORT_USAGE");v=="false"{returnh}//returnusagerecorderreturnhttp.HandlerFunc(func(whttp.ResponseWriter,r*http.Request){//countrequestsatomic.AddUint64(&requests,1)//servetherequesth.ServeHTTP(w,r)})}),)}
要想理解上面的代码含义以及功能,需要了解一下micro中plugin的功能和原理
Plugins 是一种扩展Micro功能的方式。它可以使Micro扩展和被拦截以提供其他功能。这包含日志,指标获取,追踪,认证等等。插件模型需要注册成满足plugin接口的结构体。然后在Micro启动时进行注册和设置。
以上就是plugin接口设计的目的。
当然了,不同于go-micro
中的plugin,这里的plugin主要用于micro API, Web, Sidecar, CLI.这也是用于在HTTP里面构建中间件的方法。
typePlugininterface{//全局的flagsFlags()[]cli.Flag//自命令集Commands()[]*cli.Command//Handle是HTTP请求的中间件处理器。我们将它传入到已经存在的handler中以使它可以被包裹来创建一个调用链Handler()Handler//Init方法在命令行参数被解析到时候调用,传入的参数是已经初始化后的cli.ContextInit(*cli.Context)error//plugin的名称。String()string}//Manager是plugin管理器。它存储plugins并允许他们可以被检索。//它被用于micro的所有组件中。typeManagerinterface{Plugins(...PluginOption)[]PluginRegister(Plugin,...PluginOption)error}//Handler是中间件处理器plugin.可以用来包裹一个存在的http.Handler.//需要在链中调用下一个http.HandlertypeHandlerfunc(http.Handler)http.Handler
看完了这些接口类型原型后,问题来了,如何使用他们呢。下面的例子是一个比较简单的例子,添加一个flag然后输出它的值。
packagemainimport("log""github.com/urfave/cli/v2""github.com/micro/micro/plugin")funcinit(){plugin.Register(plugin.NewPlugin(plugin.WithName("example"),plugin.WithFlag(&cli.StringFlag{Name:"example_flag",Usage:"Thisisanexamplepluginflag",EnvVars:[]string{"EXAMPLE_FLAG"},Value:"avalue",}),plugin.WithInit(func(ctx*cli.Context)error{log.Println("Gotvalueforexample_flag",ctx.String("example_flag"))returnnil}),))}
编译代码
gobuild-omicro./main.go./plugin.go
看看,是不是和我们刚开始看到的plugin匿名导入,既然整个过程的操作流程都是一样的,那我们不妨先来一探究竟
//RegisterregistersaglobalpluginsfuncRegister(pluginPlugin,opts...PluginOption)error{returndefaultManager.Register(plugin,opts...)}
在默认的管理器defaultManager上注册plugin
var(//globalpluginmanagerdefaultManager=newManager())funcnewManager()*manager{return&manager{plugins:make(map[string][]Plugin),registered:make(map[string]map[string]bool),}}
至于注册的动作其实很简单,锁保护下,进行map的操作
func(m*manager)Register(pluginPlugin,opts...PluginOption)error{options:=PluginOptions{Module:defaultModule}for_,o:=rangeopts{o(&options)}m.Lock()deferm.Unlock()name:=plugin.String()ifreg,ok:=m.registered[options.Module];ok&®[name]{returnfmt.Errorf("Pluginwithname%salreadyregistered",name)}if_,ok:=m.registered[options.Module];!ok{m.registered[options.Module]=map[string]bool{name:true}}else{m.registered[options.Module][name]=true}if_,ok:=m.plugins[options.Module];ok{m.plugins[options.Module]=append(m.plugins[options.Module],plugin)}else{m.plugins[options.Module]=[]Plugin{plugin}}returnnil}
还有一点提一句plugin.NewPlugin
在创建一个plugin时,参数是Options
结构体,那些With
开头的方法WithFlag
...
typeOptionsstruct{NamestringFlags[]cli.FlagCommands[]*cli.CommandHandlers[]HandlerInitfunc(*cli.Context)error}funcWithFlag(flag...cli.Flag)Option{returnfunc(o*Options){o.Flags=append(o.Flags,flag...)}}
都是对相关plugin属性进行初始化的。这个比较清晰就不必多说。
3.client
看完了usage
,看匿名导入的第二部分内容
_"github.com/micro/micro/v3/client/cli"_"github.com/micro/micro/v3/client/cli/init"_"github.com/micro/micro/v3/client/cli/new"_"github.com/micro/micro/v3/client/cli/signup"_"github.com/micro/micro/v3/client/cli/user"
有关客户端的一些初始化工作。
第一个是cli
funcinit(){plugin.Register(Plugin())}funcPlugin()plugin.Plugin{varrequestsuint64//createrandsource:=rand.NewSource(time.Now().UnixNano())r:=rand.New(source)returnplugin.NewPlugin(plugin.WithName("usage"),plugin.WithInit(func(c*cli.Context)error{//onlydoifenabledif!c.Bool("report_usage"){os.Setenv("MICRO_REPORT_USAGE","false")returnnil}varservicestring//setservicenameifc.Args().Len()>0&&len(c.Args().Get(0))>0{service=c.Args().Get(0)}//servicesubcommandifservice=="service"{//setasthesubcommandifv:=c.Args().Get(1);len(v)>0{service=v}}//kickoffthetrackergofunc(){//newreportu:=New(service)//initialpublishin30-60secondsd:=30+r.Intn(30)time.Sleep(time.Second*time.Duration(d))for{//getservicelists,_:=registry.ListServices()//getrequestsreqs:=atomic.LoadUint64(&requests)srvs:=uint64(len(s))//resetrequestsatomic.StoreUint64(&requests,0)//setmetricsu.Metrics.Count["instances"]=uint64(1)u.Metrics.Count["requests"]=reqsu.Metrics.Count["services"]=srvs//attempttosendreport3timesfori:=1;i<=3;i++{iferr:=Report(u);err!=nil{time.Sleep(backoff.Do(i*2))continue}break}//nowsleep24hourstime.Sleep(time.Hour*24)}}()returnnil}),plugin.WithHandler(func(hhttp.Handler)http.Handler{//onlyenableifsetifv:=os.Getenv("MICRO_REPORT_USAGE");v=="false"{returnh}//returnusagerecorderreturnhttp.HandlerFunc(func(whttp.ResponseWriter,r*http.Request){//countrequestsatomic.AddUint64(&requests,1)//servetherequesth.ServeHTTP(w,r)})}),)}0
命令行注册,主要包含以下命令行功能:
cli:用于交互式的命令行操作
call:服务调用例如 micro call greeter Say.Hello '{\"name\": \"John\"}
stream: 创建一个服务流
stats: 查询一个服务的状态
env:获取或者设置环境变量
services:罗列出所有已经注册的服务列表
第二个是clien
包中的匿名导入init
导入
funcinit(){plugin.Register(Plugin())}funcPlugin()plugin.Plugin{varrequestsuint64//createrandsource:=rand.NewSource(time.Now().UnixNano())r:=rand.New(source)returnplugin.NewPlugin(plugin.WithName("usage"),plugin.WithInit(func(c*cli.Context)error{//onlydoifenabledif!c.Bool("report_usage"){os.Setenv("MICRO_REPORT_USAGE","false")returnnil}varservicestring//setservicenameifc.Args().Len()>0&&len(c.Args().Get(0))>0{service=c.Args().Get(0)}//servicesubcommandifservice=="service"{//setasthesubcommandifv:=c.Args().Get(1);len(v)>0{service=v}}//kickoffthetrackergofunc(){//newreportu:=New(service)//initialpublishin30-60secondsd:=30+r.Intn(30)time.Sleep(time.Second*time.Duration(d))for{//getservicelists,_:=registry.ListServices()//getrequestsreqs:=atomic.LoadUint64(&requests)srvs:=uint64(len(s))//resetrequestsatomic.StoreUint64(&requests,0)//setmetricsu.Metrics.Count["instances"]=uint64(1)u.Metrics.Count["requests"]=reqsu.Metrics.Count["services"]=srvs//attempttosendreport3timesfori:=1;i<=3;i++{iferr:=Report(u);err!=nil{time.Sleep(backoff.Do(i*2))continue}break}//nowsleep24hourstime.Sleep(time.Hour*24)}}()returnnil}),plugin.WithHandler(func(hhttp.Handler)http.Handler{//onlyenableifsetifv:=os.Getenv("MICRO_REPORT_USAGE");v=="false"{returnh}//returnusagerecorderreturnhttp.HandlerFunc(func(whttp.ResponseWriter,r*http.Request){//countrequestsatomic.AddUint64(&requests,1)//servetherequesth.ServeHTTP(w,r)})}),)}1
该命令行注册的是micro init
。用于为micro的plugin
产生profile.go
。那么执行该命令到底做了什么呢?
funcinit(){plugin.Register(Plugin())}funcPlugin()plugin.Plugin{varrequestsuint64//createrandsource:=rand.NewSource(time.Now().UnixNano())r:=rand.New(source)returnplugin.NewPlugin(plugin.WithName("usage"),plugin.WithInit(func(c*cli.Context)error{//onlydoifenabledif!c.Bool("report_usage"){os.Setenv("MICRO_REPORT_USAGE","false")returnnil}varservicestring//setservicenameifc.Args().Len()>0&&len(c.Args().Get(0))>0{service=c.Args().Get(0)}//servicesubcommandifservice=="service"{//setasthesubcommandifv:=c.Args().Get(1);len(v)>0{service=v}}//kickoffthetrackergofunc(){//newreportu:=New(service)//initialpublishin30-60secondsd:=30+r.Intn(30)time.Sleep(time.Second*time.Duration(d))for{//getservicelists,_:=registry.ListServices()//getrequestsreqs:=atomic.LoadUint64(&requests)srvs:=uint64(len(s))//resetrequestsatomic.StoreUint64(&requests,0)//setmetricsu.Metrics.Count["instances"]=uint64(1)u.Metrics.Count["requests"]=reqsu.Metrics.Count["services"]=srvs//attempttosendreport3timesfori:=1;i<=3;i++{iferr:=Report(u);err!=nil{time.Sleep(backoff.Do(i*2))continue}break}//nowsleep24hourstime.Sleep(time.Hour*24)}}()returnnil}),plugin.WithHandler(func(hhttp.Handler)http.Handler{//onlyenableifsetifv:=os.Getenv("MICRO_REPORT_USAGE");v=="false"{returnh}//returnusagerecorderreturnhttp.HandlerFunc(func(whttp.ResponseWriter,r*http.Request){//countrequestsatomic.AddUint64(&requests,1)//servetherequesth.ServeHTTP(w,r)})}),)}2
根据该命令对用的执行动作,我们发现,其实就是根据该命令的参数profile
提供的参数,把相应的参数组成可导入路径,进行匿名导入,默认写到标准输出,可以通过output
选项进行指定输出路径。
第三个是clien
包中的匿名导入new
导入,用于注册micro new
命令行,该命令行用于创建一个消息模板,通过我们通过micro new helloworld && cd helloworld'
来创建一个服务时,就是通过该命令来操作的。
funcinit(){plugin.Register(Plugin())}funcPlugin()plugin.Plugin{varrequestsuint64//createrandsource:=rand.NewSource(time.Now().UnixNano())r:=rand.New(source)returnplugin.NewPlugin(plugin.WithName("usage"),plugin.WithInit(func(c*cli.Context)error{//onlydoifenabledif!c.Bool("report_usage"){os.Setenv("MICRO_REPORT_USAGE","false")returnnil}varservicestring//setservicenameifc.Args().Len()>0&&len(c.Args().Get(0))>0{service=c.Args().Get(0)}//servicesubcommandifservice=="service"{//setasthesubcommandifv:=c.Args().Get(1);len(v)>0{service=v}}//kickoffthetrackergofunc(){//newreportu:=New(service)//initialpublishin30-60secondsd:=30+r.Intn(30)time.Sleep(time.Second*time.Duration(d))for{//getservicelists,_:=registry.ListServices()//getrequestsreqs:=atomic.LoadUint64(&requests)srvs:=uint64(len(s))//resetrequestsatomic.StoreUint64(&requests,0)//setmetricsu.Metrics.Count["instances"]=uint64(1)u.Metrics.Count["requests"]=reqsu.Metrics.Count["services"]=srvs//attempttosendreport3timesfori:=1;i<=3;i++{iferr:=Report(u);err!=nil{time.Sleep(backoff.Do(i*2))continue}break}//nowsleep24hourstime.Sleep(time.Hour*24)}}()returnnil}),plugin.WithHandler(func(hhttp.Handler)http.Handler{//onlyenableifsetifv:=os.Getenv("MICRO_REPORT_USAGE");v=="false"{returnh}//returnusagerecorderreturnhttp.HandlerFunc(func(whttp.ResponseWriter,r*http.Request){//countrequestsatomic.AddUint64(&requests,1)//servetherequesth.ServeHTTP(w,r)})}),)}3
在上一篇文章中,我们进行了操作,新建一个服务,那么该命令执行的动作是什么呢?
funcinit(){plugin.Register(Plugin())}funcPlugin()plugin.Plugin{varrequestsuint64//createrandsource:=rand.NewSource(time.Now().UnixNano())r:=rand.New(source)returnplugin.NewPlugin(plugin.WithName("usage"),plugin.WithInit(func(c*cli.Context)error{//onlydoifenabledif!c.Bool("report_usage"){os.Setenv("MICRO_REPORT_USAGE","false")returnnil}varservicestring//setservicenameifc.Args().Len()>0&&len(c.Args().Get(0))>0{service=c.Args().Get(0)}//servicesubcommandifservice=="service"{//setasthesubcommandifv:=c.Args().Get(1);len(v)>0{service=v}}//kickoffthetrackergofunc(){//newreportu:=New(service)//initialpublishin30-60secondsd:=30+r.Intn(30)time.Sleep(time.Second*time.Duration(d))for{//getservicelists,_:=registry.ListServices()//getrequestsreqs:=atomic.LoadUint64(&requests)srvs:=uint64(len(s))//resetrequestsatomic.StoreUint64(&requests,0)//setmetricsu.Metrics.Count["instances"]=uint64(1)u.Metrics.Count["requests"]=reqsu.Metrics.Count["services"]=srvs//attempttosendreport3timesfori:=1;i<=3;i++{iferr:=Report(u);err!=nil{time.Sleep(backoff.Do(i*2))continue}break}//nowsleep24hourstime.Sleep(time.Hour*24)}}()returnnil}),plugin.WithHandler(func(hhttp.Handler)http.Handler{//onlyenableifsetifv:=os.Getenv("MICRO_REPORT_USAGE");v=="false"{returnh}//returnusagerecorderreturnhttp.HandlerFunc(func(whttp.ResponseWriter,r*http.Request){//countrequestsatomic.AddUint64(&requests,1)//servetherequesth.ServeHTTP(w,r)})}),)}4
首先他会获取第一个参数服务名,如果没有指定,将直接结束。提供了服务名之后,他会进行路径检测,看是否是绝对路径,这里是不提倡使用绝对路径的。如果是绝对路径也会直接返回。
在一切都就绪后,它将创建服务的整体目录。
第四个是clien
包中的匿名导入signup
导入,用户注册用于登录的命令行。我们在上一篇文章中使用的micro login
就跟这个有关系。
funcinit(){plugin.Register(Plugin())}funcPlugin()plugin.Plugin{varrequestsuint64//createrandsource:=rand.NewSource(time.Now().UnixNano())r:=rand.New(source)returnplugin.NewPlugin(plugin.WithName("usage"),plugin.WithInit(func(c*cli.Context)error{//onlydoifenabledif!c.Bool("report_usage"){os.Setenv("MICRO_REPORT_USAGE","false")returnnil}varservicestring//setservicenameifc.Args().Len()>0&&len(c.Args().Get(0))>0{service=c.Args().Get(0)}//servicesubcommandifservice=="service"{//setasthesubcommandifv:=c.Args().Get(1);len(v)>0{service=v}}//kickoffthetrackergofunc(){//newreportu:=New(service)//initialpublishin30-60secondsd:=30+r.Intn(30)time.Sleep(time.Second*time.Duration(d))for{//getservicelists,_:=registry.ListServices()//getrequestsreqs:=atomic.LoadUint64(&requests)srvs:=uint64(len(s))//resetrequestsatomic.StoreUint64(&requests,0)//setmetricsu.Metrics.Count["instances"]=uint64(1)u.Metrics.Count["requests"]=reqsu.Metrics.Count["services"]=srvs//attempttosendreport3timesfori:=1;i<=3;i++{iferr:=Report(u);err!=nil{time.Sleep(backoff.Do(i*2))continue}break}//nowsleep24hourstime.Sleep(time.Hour*24)}}()returnnil}),plugin.WithHandler(func(hhttp.Handler)http.Handler{//onlyenableifsetifv:=os.Getenv("MICRO_REPORT_USAGE");v=="false"{returnh}//returnusagerecorderreturnhttp.HandlerFunc(func(whttp.ResponseWriter,r*http.Request){//countrequestsatomic.AddUint64(&requests,1)//servetherequesth.ServeHTTP(w,r)})}),)}5
而该命令的执行动作就是注册用户的整个流程。注册成功后,后面就可以使用micro login
进行登录。
最后一个是clien
包中的匿名导入user
导入,用户打印出当前登录的用户
funcinit(){plugin.Register(Plugin())}funcPlugin()plugin.Plugin{varrequestsuint64//createrandsource:=rand.NewSource(time.Now().UnixNano())r:=rand.New(source)returnplugin.NewPlugin(plugin.WithName("usage"),plugin.WithInit(func(c*cli.Context)error{//onlydoifenabledif!c.Bool("report_usage"){os.Setenv("MICRO_REPORT_USAGE","false")returnnil}varservicestring//setservicenameifc.Args().Len()>0&&len(c.Args().Get(0))>0{service=c.Args().Get(0)}//servicesubcommandifservice=="service"{//setasthesubcommandifv:=c.Args().Get(1);len(v)>0{service=v}}//kickoffthetrackergofunc(){//newreportu:=New(service)//initialpublishin30-60secondsd:=30+r.Intn(30)time.Sleep(time.Second*time.Duration(d))for{//getservicelists,_:=registry.ListServices()//getrequestsreqs:=atomic.LoadUint64(&requests)srvs:=uint64(len(s))//resetrequestsatomic.StoreUint64(&requests,0)//setmetricsu.Metrics.Count["instances"]=uint64(1)u.Metrics.Count["requests"]=reqsu.Metrics.Count["services"]=srvs//attempttosendreport3timesfori:=1;i<=3;i++{iferr:=Report(u);err!=nil{time.Sleep(backoff.Do(i*2))continue}break}//nowsleep24hourstime.Sleep(time.Hour*24)}}()returnnil}),plugin.WithHandler(func(hhttp.Handler)http.Handler{//onlyenableifsetifv:=os.Getenv("MICRO_REPORT_USAGE");v=="false"{returnh}//returnusagerecorderreturnhttp.HandlerFunc(func(whttp.ResponseWriter,r*http.Request){//countrequestsatomic.AddUint64(&requests,1)//servetherequesth.ServeHTTP(w,r)})}),)}6
该命令包含一些子命令,比如用于修改用户的密码的子命令。
funcinit(){plugin.Register(Plugin())}funcPlugin()plugin.Plugin{varrequestsuint64//createrandsource:=rand.NewSource(time.Now().UnixNano())r:=rand.New(source)returnplugin.NewPlugin(plugin.WithName("usage"),plugin.WithInit(func(c*cli.Context)error{//onlydoifenabledif!c.Bool("report_usage"){os.Setenv("MICRO_REPORT_USAGE","false")returnnil}varservicestring//setservicenameifc.Args().Len()>0&&len(c.Args().Get(0))>0{service=c.Args().Get(0)}//servicesubcommandifservice=="service"{//setasthesubcommandifv:=c.Args().Get(1);len(v)>0{service=v}}//kickoffthetrackergofunc(){//newreportu:=New(service)//initialpublishin30-60secondsd:=30+r.Intn(30)time.Sleep(time.Second*time.Duration(d))for{//getservicelists,_:=registry.ListServices()//getrequestsreqs:=atomic.LoadUint64(&requests)srvs:=uint64(len(s))//resetrequestsatomic.StoreUint64(&requests,0)//setmetricsu.Metrics.Count["instances"]=uint64(1)u.Metrics.Count["requests"]=reqsu.Metrics.Count["services"]=srvs//attempttosendreport3timesfori:=1;i<=3;i++{iferr:=Report(u);err!=nil{time.Sleep(backoff.Do(i*2))continue}break}//nowsleep24hourstime.Sleep(time.Hour*24)}}()returnnil}),plugin.WithHandler(func(hhttp.Handler)http.Handler{//onlyenableifsetifv:=os.Getenv("MICRO_REPORT_USAGE");v=="false"{returnh}//returnusagerecorderreturnhttp.HandlerFunc(func(whttp.ResponseWriter,r*http.Request){//countrequestsatomic.AddUint64(&requests,1)//servetherequesth.ServeHTTP(w,r)})}),)}7
到这里,整个client
包的准备工作都已经结束了,而下一部分就到了server
4.server
在这里,注册micro server
命令。并运行起整个平台。
funcinit(){plugin.Register(Plugin())}funcPlugin()plugin.Plugin{varrequestsuint64//createrandsource:=rand.NewSource(time.Now().UnixNano())r:=rand.New(source)returnplugin.NewPlugin(plugin.WithName("usage"),plugin.WithInit(func(c*cli.Context)error{//onlydoifenabledif!c.Bool("report_usage"){os.Setenv("MICRO_REPORT_USAGE","false")returnnil}varservicestring//setservicenameifc.Args().Len()>0&&len(c.Args().Get(0))>0{service=c.Args().Get(0)}//servicesubcommandifservice=="service"{//setasthesubcommandifv:=c.Args().Get(1);len(v)>0{service=v}}//kickoffthetrackergofunc(){//newreportu:=New(service)//initialpublishin30-60secondsd:=30+r.Intn(30)time.Sleep(time.Second*time.Duration(d))for{//getservicelists,_:=registry.ListServices()//getrequestsreqs:=atomic.LoadUint64(&requests)srvs:=uint64(len(s))//resetrequestsatomic.StoreUint64(&requests,0)//setmetricsu.Metrics.Count["instances"]=uint64(1)u.Metrics.Count["requests"]=reqsu.Metrics.Count["services"]=srvs//attempttosendreport3timesfori:=1;i<=3;i++{iferr:=Report(u);err!=nil{time.Sleep(backoff.Do(i*2))continue}break}//nowsleep24hourstime.Sleep(time.Hour*24)}}()returnnil}),plugin.WithHandler(func(hhttp.Handler)http.Handler{//onlyenableifsetifv:=os.Getenv("MICRO_REPORT_USAGE");v=="false"{returnh}//returnusagerecorderreturnhttp.HandlerFunc(func(whttp.ResponseWriter,r*http.Request){//countrequestsatomic.AddUint64(&requests,1)//servetherequesth.ServeHTTP(w,r)})}),)}8
而在我们启动micro server
时,执行的行为为:
funcinit(){plugin.Register(Plugin())}funcPlugin()plugin.Plugin{varrequestsuint64//createrandsource:=rand.NewSource(time.Now().UnixNano())r:=rand.New(source)returnplugin.NewPlugin(plugin.WithName("usage"),plugin.WithInit(func(c*cli.Context)error{//onlydoifenabledif!c.Bool("report_usage"){os.Setenv("MICRO_REPORT_USAGE","false")returnnil}varservicestring//setservicenameifc.Args().Len()>0&&len(c.Args().Get(0))>0{service=c.Args().Get(0)}//servicesubcommandifservice=="service"{//setasthesubcommandifv:=c.Args().Get(1);len(v)>0{service=v}}//kickoffthetrackergofunc(){//newreportu:=New(service)//initialpublishin30-60secondsd:=30+r.Intn(30)time.Sleep(time.Second*time.Duration(d))for{//getservicelists,_:=registry.ListServices()//getrequestsreqs:=atomic.LoadUint64(&requests)srvs:=uint64(len(s))//resetrequestsatomic.StoreUint64(&requests,0)//setmetricsu.Metrics.Count["instances"]=uint64(1)u.Metrics.Count["requests"]=reqsu.Metrics.Count["services"]=srvs//attempttosendreport3timesfori:=1;i<=3;i++{iferr:=Report(u);err!=nil{time.Sleep(backoff.Do(i*2))continue}break}//nowsleep24hourstime.Sleep(time.Hour*24)}}()returnnil}),plugin.WithHandler(func(hhttp.Handler)http.Handler{//onlyenableifsetifv:=os.Getenv("MICRO_REPORT_USAGE");v=="false"{returnh}//returnusagerecorderreturnhttp.HandlerFunc(func(whttp.ResponseWriter,r*http.Request){//countrequestsatomic.AddUint64(&requests,1)//servetherequesth.ServeHTTP(w,r)})}),)}9
如果在运行server
时,提供了参数,将打印出子命令帮助信息并直接退出。
之后,遍历下面的切片
typePlugininterface{//全局的flagsFlags()[]cli.Flag//自命令集Commands()[]*cli.Command//Handle是HTTP请求的中间件处理器。我们将它传入到已经存在的handler中以使它可以被包裹来创建一个调用链Handler()Handler//Init方法在命令行参数被解析到时候调用,传入的参数是已经初始化后的cli.ContextInit(*cli.Context)error//plugin的名称。String()string}//Manager是plugin管理器。它存储plugins并允许他们可以被检索。//它被用于micro的所有组件中。typeManagerinterface{Plugins(...PluginOption)[]PluginRegister(Plugin,...PluginOption)error}//Handler是中间件处理器plugin.可以用来包裹一个存在的http.Handler.//需要在链中调用下一个http.HandlertypeHandlerfunc(http.Handler)http.Handler0
进行服务的注册.所有的服务运行,都是通过micro service [name]
。
typePlugininterface{//全局的flagsFlags()[]cli.Flag//自命令集Commands()[]*cli.Command//Handle是HTTP请求的中间件处理器。我们将它传入到已经存在的handler中以使它可以被包裹来创建一个调用链Handler()Handler//Init方法在命令行参数被解析到时候调用,传入的参数是已经初始化后的cli.ContextInit(*cli.Context)error//plugin的名称。String()string}//Manager是plugin管理器。它存储plugins并允许他们可以被检索。//它被用于micro的所有组件中。typeManagerinterface{Plugins(...PluginOption)[]PluginRegister(Plugin,...PluginOption)error}//Handler是中间件处理器plugin.可以用来包裹一个存在的http.Handler.//需要在链中调用下一个http.HandlertypeHandlerfunc(http.Handler)http.Handler1
在这当中,1.如果未设置proxy_address
,使用默认的本地网络proxy = "127.0.0.1:8443"
2.获取环境变量中我们关心的值。
在一系列的准备工作就绪后,调用service的Run方法启动起server
typePlugininterface{//全局的flagsFlags()[]cli.Flag//自命令集Commands()[]*cli.Command//Handle是HTTP请求的中间件处理器。我们将它传入到已经存在的handler中以使它可以被包裹来创建一个调用链Handler()Handler//Init方法在命令行参数被解析到时候调用,传入的参数是已经初始化后的cli.ContextInit(*cli.Context)error//plugin的名称。String()string}//Manager是plugin管理器。它存储plugins并允许他们可以被检索。//它被用于micro的所有组件中。typeManagerinterface{Plugins(...PluginOption)[]PluginRegister(Plugin,...PluginOption)error}//Handler是中间件处理器plugin.可以用来包裹一个存在的http.Handler.//需要在链中调用下一个http.HandlertypeHandlerfunc(http.Handler)http.Handler2
结束了上的工作之后,开始进入最后一部分内容的准备工作
5.service
首先是关于鉴权相关命令行注册, micro auth
命令。该命令涵盖一些子命令,包含
list:罗列出鉴权资讯
create: 创建鉴权资源
delete:删除鉴权资源
login:登录用户
logout:登出用户
typePlugininterface{//全局的flagsFlags()[]cli.Flag//自命令集Commands()[]*cli.Command//Handle是HTTP请求的中间件处理器。我们将它传入到已经存在的handler中以使它可以被包裹来创建一个调用链Handler()Handler//Init方法在命令行参数被解析到时候调用,传入的参数是已经初始化后的cli.ContextInit(*cli.Context)error//plugin的名称。String()string}//Manager是plugin管理器。它存储plugins并允许他们可以被检索。//它被用于micro的所有组件中。typeManagerinterface{Plugins(...PluginOption)[]PluginRegister(Plugin,...PluginOption)error}//Handler是中间件处理器plugin.可以用来包裹一个存在的http.Handler.//需要在链中调用下一个http.HandlertypeHandlerfunc(http.Handler)http.Handler3
在进行了用户的鉴权后,第二部分是关于service
相关命令行的准备工作
typePlugininterface{//全局的flagsFlags()[]cli.Flag//自命令集Commands()[]*cli.Command//Handle是HTTP请求的中间件处理器。我们将它传入到已经存在的handler中以使它可以被包裹来创建一个调用链Handler()Handler//Init方法在命令行参数被解析到时候调用,传入的参数是已经初始化后的cli.ContextInit(*cli.Context)error//plugin的名称。String()string}//Manager是plugin管理器。它存储plugins并允许他们可以被检索。//它被用于micro的所有组件中。typeManagerinterface{Plugins(...PluginOption)[]PluginRegister(Plugin,...PluginOption)error}//Handler是中间件处理器plugin.可以用来包裹一个存在的http.Handler.//需要在链中调用下一个http.HandlertypeHandlerfunc(http.Handler)http.Handler4
第三部分关于config
的命令行注册,该命令行用于管理配置项的值的设置,包括获取,删除,设置。
typePlugininterface{//全局的flagsFlags()[]cli.Flag//自命令集Commands()[]*cli.Command//Handle是HTTP请求的中间件处理器。我们将它传入到已经存在的handler中以使它可以被包裹来创建一个调用链Handler()Handler//Init方法在命令行参数被解析到时候调用,传入的参数是已经初始化后的cli.ContextInit(*cli.Context)error//plugin的名称。String()string}//Manager是plugin管理器。它存储plugins并允许他们可以被检索。//它被用于micro的所有组件中。typeManagerinterface{Plugins(...PluginOption)[]PluginRegister(Plugin,...PluginOption)error}//Handler是中间件处理器plugin.可以用来包裹一个存在的http.Handler.//需要在链中调用下一个http.HandlertypeHandlerfunc(http.Handler)http.Handler5
第四部分是关于network
相关的设置的命令行注册。该命令用于管理micro service的网络,包含一些子命令
connect:连接指定网络
connections:列出直接连接的网络
graph:获取网络图
nodes:获取网络节点
routes:获取网络路由
services:获取网络服务
call:调用服务
typePlugininterface{//全局的flagsFlags()[]cli.Flag//自命令集Commands()[]*cli.Command//Handle是HTTP请求的中间件处理器。我们将它传入到已经存在的handler中以使它可以被包裹来创建一个调用链Handler()Handler//Init方法在命令行参数被解析到时候调用,传入的参数是已经初始化后的cli.ContextInit(*cli.Context)error//plugin的名称。String()string}//Manager是plugin管理器。它存储plugins并允许他们可以被检索。//它被用于micro的所有组件中。typeManagerinterface{Plugins(...PluginOption)[]PluginRegister(Plugin,...PluginOption)error}//Handler是中间件处理器plugin.可以用来包裹一个存在的http.Handler.//需要在链中调用下一个http.HandlertypeHandlerfunc(http.Handler)http.Handler6
第五部分,主要涉及micro run/update/kill/status/logs
等相关命令的注册,这些命令都是管理特定的服务的相关操作。
typePlugininterface{//全局的flagsFlags()[]cli.Flag//自命令集Commands()[]*cli.Command//Handle是HTTP请求的中间件处理器。我们将它传入到已经存在的handler中以使它可以被包裹来创建一个调用链Handler()Handler//Init方法在命令行参数被解析到时候调用,传入的参数是已经初始化后的cli.ContextInit(*cli.Context)error//plugin的名称。String()string}//Manager是plugin管理器。它存储plugins并允许他们可以被检索。//它被用于micro的所有组件中。typeManagerinterface{Plugins(...PluginOption)[]PluginRegister(Plugin,...PluginOption)error}//Handler是中间件处理器plugin.可以用来包裹一个存在的http.Handler.//需要在链中调用下一个http.HandlertypeHandlerfunc(http.Handler)http.Handler7
最后一部分,主要涉及关于存储相关的micro store
命令注册,包括一些子命令
read:从存储中读取记录
list:罗列出一个存储中所有的key
write:写入一条记录到存储中
delete:删除存储中的一条记录
databases:罗列出已知存储中的所有数据库
tables:罗列出指定数据库中所有的表
snapshot:备份一个存储
sync:同步一份存储到新的里面
restore:从一份快照中恢复存储
typePlugininterface{//全局的flagsFlags()[]cli.Flag//自命令集Commands()[]*cli.Command//Handle是HTTP请求的中间件处理器。我们将它传入到已经存在的handler中以使它可以被包裹来创建一个调用链Handler()Handler//Init方法在命令行参数被解析到时候调用,传入的参数是已经初始化后的cli.ContextInit(*cli.Context)error//plugin的名称。String()string}//Manager是plugin管理器。它存储plugins并允许他们可以被检索。//它被用于micro的所有组件中。typeManagerinterface{Plugins(...PluginOption)[]PluginRegister(Plugin,...PluginOption)error}//Handler是中间件处理器plugin.可以用来包裹一个存在的http.Handler.//需要在链中调用下一个http.HandlertypeHandlerfunc(http.Handler)http.Handler8
至此,整个初始化准备工作都已经完成。。。。
开启整个命令行程序。
typePlugininterface{//全局的flagsFlags()[]cli.Flag//自命令集Commands()[]*cli.Command//Handle是HTTP请求的中间件处理器。我们将它传入到已经存在的handler中以使它可以被包裹来创建一个调用链Handler()Handler//Init方法在命令行参数被解析到时候调用,传入的参数是已经初始化后的cli.ContextInit(*cli.Context)error//plugin的名称。String()string}//Manager是plugin管理器。它存储plugins并允许他们可以被检索。//它被用于micro的所有组件中。typeManagerinterface{Plugins(...PluginOption)[]PluginRegister(Plugin,...PluginOption)error}//Handler是中间件处理器plugin.可以用来包裹一个存在的http.Handler.//需要在链中调用下一个http.HandlertypeHandlerfunc(http.Handler)http.Handler9