go micro config

micro.newService()中newOptionsweb

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中json

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()左作了什麼segmentfault

  1. 初始化並設置opts,建立exit用於監聽退出信號,設置opts
  2. 設置默認loader,c.opts.Loader默認是memory memory.NewLoader()[config/loader/memory/memory.go]app

    1. 初始化並設置opts,包含Reader[默認json]
    2. 初始化memory{}
    3. 設置m.sets,並watch()每一個options.Source,看看watch()作了什麼函數

      1. 定義watch()函數插件

        1. 調用watcher.Next(),下面看看next()作了什麼code

          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()router

          1. 獲取全部watcher,若是版本有更新,則發送watcher.updates信號
      2. 調用Watch()函數返回watcher,注意W是大寫,調用的是memory.Watch()server

        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這塊實際上是比較獨立的包,能夠在其餘項目中引用。

go micro 分析系列文章
go micro server 啓動分析
go micro client
go micro broker
go micro cmd
go micro config
go micro store
go micro registry
go micro router
go micro runtime
go micro transport
go micro web
go micro registry 插件consul
go micro plugin
go micro jwt 網關鑑權
go micro 鏈路追蹤
go micro 熔斷與限流
go micro wrapper 中間件
go micro metrics 接入Prometheus、Grafana

相關文章
相關標籤/搜索