Skip to content

Latest commit

 

History

History
99 lines (92 loc) · 3.45 KB

viper.md

File metadata and controls

99 lines (92 loc) · 3.45 KB

Table of Contents generated with DocToc

Viper

Viper是Go应用程序的完整配置解决方案,包括12-Factor应用程序。

支持

  • 设置默认值
  • 从JSON,TOML,YAML,HCL和Java属性配置文件中读取
  • 实时观看和重新读取配置文件(可选)
  • 从环境变量中读取
  • 从远程配置系统(etcd或Consul)读取,并观察变化
  • 从命令行标志读取
  • 从缓冲区读取
  • 设置显式值

Note: 目前Viper支持的Remote远程读取配置如 etcd, consul;目前还没有对Nacos进行支持,参考第三方https://github.com/yoyofxteam/nacos-viper-remote

监听文件变化

func (v *Viper) WatchConfig() {
	// 保证监听器初始化
	initWG := sync.WaitGroup{}
	initWG.Add(1)
	go func() {
		// 调用NewWatcher创建一个监听器
		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			log.Fatal(err)
		}
		defer watcher.Close()
		//获取配置文件路径,抽出文件名、目录,配置文件如果是一个符号链接,获得链接指向的路径
		// we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way
		filename, err := v.getConfigFile()
		if err != nil {
			log.Printf("error: %v\n", err)
			initWG.Done()
			return
		}

		configFile := filepath.Clean(filename)
		configDir, _ := filepath.Split(configFile)
		realConfigFile, _ := filepath.EvalSymlinks(filename)

		// eventsWG是在事件通道关闭,或配置被删除了,或遇到错误时退出事件处理循环
		eventsWG := sync.WaitGroup{}
		eventsWG.Add(1)
		go func() {
			for {
				select {
				case event, ok := <-watcher.Events:
					if !ok { // 'Events' channel is closed
						eventsWG.Done()
						return
					}
					currentConfigFile, _ := filepath.EvalSymlinks(filename)
					// we only care about the config file with the following cases:
					// 1 - if the config file was modified or created
					// 2 - if the real path to the config file changed (eg: k8s ConfigMap replacement)
					const writeOrCreateMask = fsnotify.Write | fsnotify.Create
					if (filepath.Clean(event.Name) == configFile &&
						event.Op&writeOrCreateMask != 0) ||
						(currentConfigFile != "" && currentConfigFile != realConfigFile) {
						realConfigFile = currentConfigFile
						err := v.ReadInConfig()
						if err != nil {
							log.Printf("error reading config file: %v\n", err)
						}
						if v.onConfigChange != nil {
							v.onConfigChange(event)
						}
					} else if filepath.Clean(event.Name) == configFile &&
						event.Op&fsnotify.Remove&fsnotify.Remove != 0 {
						eventsWG.Done()
						return
					}

				case err, ok := <-watcher.Errors:
					if ok { // 'Errors' channel is not closed
						log.Printf("watcher error: %v\n", err)
					}
					eventsWG.Done()
					return
				}
			}
		}()
		// 监听配置文件所在目录
		watcher.Add(configDir)
		initWG.Done()   // done initializing the watch in this go routine, so the parent routine can move on...
		eventsWG.Wait() // now, wait for event loop to end in this go-routine...
	}()
	initWG.Wait() // make sure that the go routine above fully ended before returning
}