go

go-micro

go-micro 启动流程分析

Posted by Liangjf on December 31, 2019

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来实现接口,所以默认的服务发现是组播DNS

      func 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")
)