乐趣区

关于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 这块其实是比拟独立的包,能够在其余我的项目中援用。

退出移动版