go-micro 启动流程分析
实例化一个服务对象
micro.NewService(github.com\micro\go-micro@v1.11.1\service)
-
实例化各组件(Broker、Cmd 、Client 、Server 、Registry 、Transport),并用自定义的插件替换默认插件
// Option定义为一个方法,接受Options类型的指针参数 type Option func(*Options) ... // 创建并返回一个服务:接收Option函数类型的不定向参数列表 func NewService(opts ...Option) Service { return newService(opts...) } ... // 内部真正创建服务的方法 func newService(opts ...Option) Service { // 关键步骤:利用opts函数列表初始化服务 options := newOptions(opts...) ... // 返回初始化的服务 return &service{ opts: options, } }
go-micro这里主要使用了函数选项模式来实现默认参数和可选参数
Options插件结构
// go-micro是插件化实现的,Options存放的是所有插件
type Options struct {
Broker broker.Broker
Cmd cmd.Cmd
Client client.Client
Server server.Server
Registry registry.Registry
Transport transport.Transport
// Before and After funcs
BeforeStart []func() error
BeforeStop []func() error
AfterStart []func() error
AfterStop []func() error
// Other options for implementations of the interface
// can be stored in a context
Context context.Context
}
2、实例化Options
- 1、实例化Options,并且默认赋值各个插件。
-
2、调用各个插件的参数选项,对各个插件重新自定义赋值,实现插件化
func newOptions(opts ...Option) Options { opt := Options{ Broker: broker.DefaultBroker, Cmd: cmd.DefaultCmd, Client: client.DefaultClient, Server: server.DefaultServer, Registry: registry.DefaultRegistry, Transport: transport.DefaultTransport, Context: context.Background(), } for _, o := range opts { o(&opt) } return opt }
Broker服务选项
- 返回一个Option类型的函数(闭包):接受Options类型指针参数并修改
-
若有自定义的Broker插件,就会通过newOptions中的遍历opts来调用此函数实现对Broker的自定义参数赋值
func Broker(b broker.Broker) Option { return func(o *Options) { o.Broker = b // Update Client and Server o.Client.Init(client.Broker(b)) o.Server.Init(server.Broker(b)) } } // 同样的,下面所有的服务选项参数都是有一个对应的赋值闭包函数 func Cmd(c cmd.Cmd) Option { return func(o *Options) { o.Cmd = c } } func Client(c client.Client) Option { return func(o *Options) { o.Client = c } } ...
着重看注册插件
o.Registry
是插件注册对象,github.com\micro\go-micro@v1.11.1\registry\registry.go
定义了关于Registry的接口registry.go
中除了定义接口外,还定义了一个全局默认DefaultRegistry = NewRegistry()
-
github.com\micro\go-micro@v1.11.1\registry\mdns_registry.go
通过组播dns(组播DNS)mdnsRegistry来实现接口,所以默认的服务发现是组播DNSfunc Registry(r registry.Registry) Option { return func(o *Options) { o.Registry = r // Update Client and Server o.Client.Init(client.Registry(r)) o.Server.Init(server.Registry(r)) // Update Selector o.Client.Options().Selector.Init(selector.Registry(r)) // Update Broker o.Broker.Init(broker.Registry(r)) } }
注册插件
-
顺便提一下
github.com\micro\go-micro@v1.11.1\registry\mdns_registry.go
- 就是此函数把插件存放到
services map[string][]*mdnsEntry
结构中, -
在
(m *mdnsRegistry) Init(opts ...Option)
对每个插件调用上面Option的服务选项参数来对每个要注册的插件进行各自的初始化func (m *mdnsRegistry) Register(service *Service, opts ...RegisterOption) error { m.Lock() defer m.Unlock() entries, ok := m.services[service.Name] ... }
到此,go-micro的服务选项参数,插件化的实例化,到各组件的初始化流程分析完了。
总的来说是go-micro的插件化是借助go的接口和闭包来实现服务选项的【函数选项模式】。达到增加插件,注册插件与原有代码解耦的目的,便于增删插件注册。
函数选项模式
下面附带一个 函数选项模式 的demo:
- register.go
- options.go
- service.go
- micro.go
register.go
///定义默认config结构体变量,方便外部引用
var DefaultOptions Options
// option 定义为一个方法,接受Options类型的指针参数
// 对接收的参数列表调用(&d),达到对应参数调用传入的函数的目的
type Options func(*Options)
options.go
//定义选项config结构体
type Options struct{
name string
}
//应用函数选项配置
func newOptions(opts ...Options) {
opt := DefaultOptions{
name: "test",
}
for _, o := range opts {
o(&opt)
}
}
//定义配置选项函数
func Name(name string) options {
return func(o *options) {
o.name = n
}
}
service.go
//定义服务对象结构体
type service struct {
opts Options
}
//服务对象实例化
func newService(opts ...Option) Service {
options := newOptions(opts...)
return &service{
opts: options,
}
}
micro.go
//对外暴露服务对象实例化的函数
func NewService(opts ...Option) Service {
return newService(opts...)
}
main.go
//调用,重新自定义赋值
service := micro.NewService(
micro.Name("liangjf")
)