Go语言配置viper

239 阅读3分钟

介绍

Viper适用于Go应用程序的完整配置解决方案,并且能处理所有类型的配置需求和格式。

  • 设置默认值
  • 读取JSON,TOML,YAML,HCL,enfile和java properties格式的配置文件读取配置信息
  • 实时监控和读取配置文件(可选)
  • 从环境变量中读取
  • 从远程配置系统(etcd/consul)读取并监控配置变化
  • 从命令行参数读取配置
  • 从buffer读取配置
  • 显示配置值

安装

go get github.com/spf13/viper

基本使用

设置默认值

viper.SetDefault("ContentDir", "content")
viper.SetDefault("LayoutDir", "layouts")
viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})

读取配置文件

viper.SetConfigFile("./config.yaml") // 指定配置文件路径
viper.SetConfigName("config") // 配置文件名称(无扩展名)
viper.SetConfigType("yaml") // 如果配置文件的名称中没有扩展名,则需要配置此项
viper.AddConfigPath("/etc/appname/")   // 查找配置文件所在的路径
viper.AddConfigPath("$HOME/.appname")  // 多次调用以添加多个搜索路径
viper.AddConfigPath(".")               // 还可以在工作目录中查找配置
err := viper.ReadInConfig() // 查找并读取配置文件
if err != nil { // 处理读取配置文件的错误
	panic(fmt.Errorf("Fatal error config file: %s \n", err))
}

写入配置文件

  • WriteConfig - 将当前的viper配置写入预定义的路径并覆盖(如果存在的话)。如果没有预定义的路径,则报错。
  • SafeWriteConfig - 将当前的viper配置写入预定义的路径。如果没有预定义的路径,则报错。如果存在,将不会覆盖当前的配置文件。
  • WriteConfigAs - 将当前的viper配置写入给定的文件路径。将覆盖给定的文件(如果它存在的话)。
  • SafeWriteConfigAs - 将当前的viper配置写入给定的文件路径。不会覆盖给定的文件(如果它存在的话)。
viper.WriteConfig() // 将当前配置写入“viper.AddConfigPath()”和“viper.SetConfigName”设置的预定义路径
viper.SafeWriteConfig()
viper.WriteConfigAs("/path/to/my/.config")
viper.SafeWriteConfigAs("/path/to/my/.config") // 因为该配置文件写入过,所以会报错
viper.SafeWriteConfigAs("/path/to/my/.other_config")

监控并重新读取配置文件

Viper支持在运行时实时读取配置文件的功能。

需要重新启动服务器以使配置生效的日子已经一去不复返了,viper驱动的应用程序可以在运行时读取配置文件的更新,而不会错过任何消息。

只需告诉viper实例watchConfig。可选地,你可以为Viper提供一个回调函数,以便在每次发生更改时运行。

确保在调用WatchConfig()之前添加了所有的配置路径。

viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
  // 配置文件发生变更之后会调用的回调函数
	fmt.Println("Config file changed:", e.Name)
}

从consul或etcd中读取

etcd


viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json")
viper.SetConfigType("json") // 因为在字节流中没有文件扩展名,所以这里需要设置下类型。支持的扩展名有 "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv"
err := viper.ReadRemoteConfig()

consul

你需要 Consul Key/Value存储中设置一个Key保存包含所需配置的JSON值。例如,创建一个keyMY_CONSUL_KEY将下面的值存入Consul key/value 存储:

{
    "port": 8080,
    "hostname": "liwenzhou.com"
}
viper.AddRemoteProvider("consul", "localhost:8500", "MY_CONSUL_KEY")
viper.SetConfigType("json") // 需要显示设置成json
err := viper.ReadRemoteConfig()

fmt.Println(viper.Get("port")) // 8080
fmt.Println(viper.Get("hostname")) // liwenzhou.com

go简单集成

func Viper(path ...string) *viper.Viper {
	var config string

	//读取配置优先级,先读取命令行>环境变量>默认值
	if len(path) == 0 {
		flag.StringVar(&config, "c", "", "choose congif file")
		flag.Parse()
		if config == "" {
			if configEnv := os.Getenv(utils.ConfigEnv); configEnv == "" {
				config = utils.ConfigFile
				fmt.Printf("正在使用默認值%s",config)
			}else{
				config=configEnv
				fmt.Printf("正在使用环境变量%s",configEnv)
			}
		}
	}else{
		config=path[0]
		fmt.Printf("使用传入的配置文件%s",config)
	}

	v:=viper.New()
	v.SetConfigFile(config)
	v.SetConfigType("yaml")
	err:=v.ReadInConfig()
	if err!=nil{
		panic(fmt.Errorf("fatal error config file %s",err).(any))
	}
	//实时监听配置的变更
	v.WatchConfig()
	//配置变更回调函数
	v.OnConfigChange(func(e fsnotify.Event) {
		fmt.Println("config file changed",e.Name)
		fmt.Println("config file changed",global.GVA_CONFIG.Redis)
		if err:=v.Unmarshal(&global.GVA_CONFIG);err!=nil{
			fmt.Println(err)
		}
	})

	//上面只有配置变更才会执行,所以需要初始化映射配置
	if err := v.Unmarshal(&global.GVA_CONFIG); err != nil {
		fmt.Println(err)
	}


	return v
}