关于micro:go-micro-config

micro.newService()中newOptions

func newOptions(opts ...Option) Options {
    opt := Options{
        Auth:      auth.DefaultAuth,
        Broker:    broker.DefaultBroker,
        Cmd:       cmd.DefaultCmd,
        Config:    config.DefaultConfig,
        Client:    client.DefaultClient,
        Server:    server.DefaultServer,
        Store:     store.DefaultStore,
        Registry:  registry.DefaultRegistry,
        Router:    router.DefaultRouter,
        Runtime:   runtime.DefaultRuntime,
        Transport: transport.DefaultTransport,
        Context:   context.Background(),
        Signal:    true,
    }

    for _, o := range opts {
        o(&opt)
    }

    return opt
}

初始化了一堆根底设置,来看看config
config.DefaultConfig,
在config/config.go中

var (
    // Default Config Manager
    DefaultConfig, _ = NewConfig()
)

// NewConfig returns new config
func NewConfig(opts ...Option) (Config, error) {
    return newConfig(opts...)
}

func newConfig(opts ...Option) (Config, error) {
    var c config

    c.Init(opts...)
    go c.run()

    return &c, nil
}

func (c *config) Init(opts ...Option) error {
    c.opts = Options{
        Reader: json.NewReader(),
    }
    c.exit = make(chan bool)
    for _, o := range opts {
        o(&c.opts)
    }

    // default loader uses the configured reader
    if c.opts.Loader == nil {
        c.opts.Loader = memory.NewLoader(memory.WithReader(c.opts.Reader))
    }

    err := c.opts.Loader.Load(c.opts.Source...)
    if err != nil {
        return err
    }

    c.snap, err = c.opts.Loader.Snapshot()
    if err != nil {
        return err
    }

    c.vals, err = c.opts.Reader.Values(c.snap.ChangeSet)
    if err != nil {
        return err
    }

    return nil
}

func (c *config) run() {
    watch := func(w loader.Watcher) error {
        for {
            // get changeset
            snap, err := w.Next()
            if err != nil {
                return err
            }

            c.Lock()

            if c.snap.Version >= snap.Version {
                c.Unlock()
                continue
            }

            // save
            c.snap = snap

            // set values
            c.vals, _ = c.opts.Reader.Values(snap.ChangeSet)

            c.Unlock()
        }
    }

    for {
        w, err := c.opts.Loader.Watch()
        if err != nil {
            time.Sleep(time.Second)
            continue
        }

        done := make(chan bool)

        // the stop watch func
        go func() {
            select {
            case <-done:
            case <-c.exit:
            }
            w.Stop()
        }()

        // block watch
        if err := watch(w); err != nil {
            // do something better
            time.Sleep(time.Second)
        }

        // close done chan
        close(done)

        // if the config is closed exit
        select {
        case <-c.exit:
            return
        default:
        }
    }
}

看看Init()左做了什么

  1. 初始化并设置opts,创立exit用于监听退出信号,设置opts
  2. 设置默认loader,c.opts.Loader默认是memory memory.NewLoader()[config/loader/memory/memory.go]

    1. 初始化并设置opts,蕴含Reader[默认json]
    2. 初始化memory{}
    3. 设置m.sets,并watch()每个options.Source,看看watch()做了什么

      1. 定义watch()函数

        1. 调用watcher.Next(),上面看看next()做了什么

          1. 定义update()函数,返回loader.Snapshot{}
          2. 监听watcher.exit,watcher.updates信号,有更新时且版本更新时,调用下面的update()函数,更新watcher.value并返回loader.Snapshot{}
        2. 保留m.sets[idx],值为loader.Snapshot{}
        3. 合并所有m.sets
        4. 读取所有值到m.vals,保留快照到m.snap
        5. 调用update()

          1. 获取所有watcher,如果版本有更新,则发送watcher.updates信号
      2. 调用Watch()函数返回watcher,留神W是大写,调用的是memory.Watch()

        1. 调用Get(),返回m.vals.Get(path…)
        2. 初始化watcher,并增加到m.watchers【双向链表】
        3. 开协程,监听watcher.exit信号,收到信号从watchers中移除以后watcher
      3. 开协程,监听实现信号done和exit信号,收到信号后执行Stop(),敞开exit,updates这2个channel
      4. 调用下面定义的watch()
      5. 敞开done channel,监听m.exit信号
  3. 调用c.opts.Loader.Load()

    1. 循环所有source,更新m.sources,m.sets,并watch()所有source
    2. 调用reload()

      1. 合并所有sets
      2. 设置m.vals,m.snap
      3. 调用m.update()
  4. 调用c.opts.Loader.Snapshot()

    1. 如曾经load,间接复制一份并返回m.snap
    2. 没载入就调用Sync()同步配置
    3. 复制一份m.snap返回
  5. 调用c.opts.Reader.Values(),赋值config.vals【reader.Values类型】

绕来绕去,终于完了。
主流程其实并不简单,次要是波及到watch更新,所以比拟绕。
config这块其实是比拟独立的包,能够在其余我的项目中援用。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理