比较有名的方案有
支持多种配置文件格式,包括 JSON,TOML,YAML,HECL,envfile,甚至还包括Java properties
支持为配置项设置默认值
可以通过命令行参数覆盖指定的配置项
支持参数别名
viper 按照这个优先级(从高到低)获取配置项的取值:
explicit call to Set: 在代码逻辑中通过viper.Set()直接设置配置项的值
flag:命令行参数
env:环境变量
config:配置文件
key/value store:etcd或者consul
default:默认值
按照这个优先级(从高到低)获取配置项的取值:
explicit call to Set: 在代码逻辑中通过viper.Set()直接设置配置项的值
flag:命令行参数
env:环境变量
config:配置文件
key/value store:etcd或者consul
default:默认值
优先级
验证一下 viper.Set() 的优先级高于 配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package mainimport ( "fmt" "github.com/spf13/viper" ) func main () { loadConfig() } func loadConfig () { configVar := "shuang-config.yaml" configVar = "" viper.Set("Global.Source" , "优先级最高" ) if configVar != "" { viper.SetConfigFile(configVar) } else { viper.SetConfigName("cui-config" ) viper.AddConfigPath("/etc/myapp" ) viper.AddConfigPath("$HOME/.myapp/" ) viper.AddConfigPath("." ) } err := viper.ReadInConfig() if err != nil { panic (fmt.Errorf("error reading config: %s" , err)) } fmt.Printf("到底用的是哪个配置文件: '%s'\n" , viper.ConfigFileUsed()) fmt.Printf("Global.Source这个字段的值为: '%s'\n" , viper.GetString("global.source" )) }
输出:
1 2 到底用的是哪个配置文件: '/Users/fliter/config-demo/cui-config.yaml' Global.Source这个字段的值为: '优先级最高'
验证一下 环境变量 的优先级高于 配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package mainimport ( "fmt" "github.com/spf13/viper" ) func main () { loadConfig() } func loadConfig () { configVar := "shuang-config.yaml" configVar = "" viper.Set("Global.Source" , "优先级最高" ) viper.AutomaticEnv() if configVar != "" { viper.SetConfigFile(configVar) } else { viper.SetConfigName("cui-config" ) viper.AddConfigPath("/etc/myapp" ) viper.AddConfigPath("$HOME/.myapp/" ) viper.AddConfigPath("." ) } err := viper.ReadInConfig() if err != nil { panic (fmt.Errorf("error reading config: %s" , err)) } fmt.Printf("到底用的是哪个配置文件: '%s'\n" , viper.ConfigFileUsed()) fmt.Printf("LANG这个字段的值为: '%s'\n" , viper.GetString("LANG" )) }
viper.AutomaticEnv()会绑定所有环境变量,
如果只希望绑定特定的,可以使用SetEnvPrefix(“global.source”, “MYAPP_GLOAL_SOURCE”),注意这个函数不会自动加上MYAPP的前缀.
验证一下 命令行参数的优先级高于 配置文件
viper可以配合pflag来使用,pflag可以理解为标准库flag的一个增强版,viper可以绑定到pflag上
和cobra,viper一样,pflag也是同一作者的作品
验证一下 默认值的优先级低于 配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package mainimport ( "fmt" "github.com/spf13/viper" ) func main () { loadConfig() } func loadConfig () { configVar := "shuang-config.yaml" configVar = "" viper.AutomaticEnv() viper.SetDefault("Global.Source" , "优先级最低" ) if configVar != "" { viper.SetConfigFile(configVar) } else { viper.SetConfigName("cui-config" ) viper.AddConfigPath("/etc/myapp" ) viper.AddConfigPath("$HOME/.myapp/" ) viper.AddConfigPath("." ) } err := viper.ReadInConfig() if err != nil { panic (fmt.Errorf("error reading config: %s" , err)) } fmt.Printf("到底用的是哪个配置文件: '%s'\n" , viper.ConfigFileUsed()) fmt.Printf("Global.Source这个字段的值为: '%s'\n" , viper.GetString("Global.Source" )) }
Watch机制(配置更新后 热加载)
该机制可以监听配置文件的修改, 这样就实现了热加载,修改配置后,无需重启服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 package mainimport ( "fmt" "time" "github.com/fsnotify/fsnotify" "github.com/spf13/viper" ) func main () { loadConfig() } func loadConfig () { configVar := "shuang-config.yaml" configVar = "" if configVar != "" { viper.SetConfigFile(configVar) } else { viper.SetConfigName("cui-config" ) viper.AddConfigPath("/etc/myapp" ) viper.AddConfigPath("$HOME/.myapp/" ) viper.AddConfigPath("." ) } viper.WatchConfig() viper.OnConfigChange(func (e fsnotify.Event) { fmt.Printf("配置文件 %s 发生了更改!!! 最新的Global.Source这个字段的值为 %s:" , e.Name, viper.GetString("Global.Source" )) }) err := viper.ReadInConfig() if err != nil { panic (fmt.Errorf("error reading config: %s" , err)) } fmt.Printf("到底用的是哪个配置文件: '%s'\n" , viper.ConfigFileUsed()) fmt.Printf("Global.Source这个字段的值为: '%s'\n" , viper.GetString("Global.Source" )) time.Sleep(10000e9 ) }
Go viper 配置文件读取工具
动态获取配置文件(viper)
Configor: 一个Golang配置工具,支持YAML,JSON,TOML,Shell环境,支持热加载
出自jinzhu大佬
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package mainimport ( "fmt" "github.com/jinzhu/configor" ) type Config struct { APPName string `default:"app name"` DB struct { Name string User string `default:"root"` Password string `required:"true" env:"DBPassword"` Port uint `default:"3306"` } Contacts []struct { Name string Email string `required:"true"` } } func main () { var conf = Config{} err := configor.Load(&conf, "config.yml" ) if err != nil { panic (err) } fmt.Printf("%v \n" , conf) }
开启 测试模式 or 详细模式
既可以在代码中显式开启,如 err := configor.New(&configor.Config{Debug: true}).Load(&conf, "config.yml")
也可以通过环境变量开启,如 CONFIGOR_DEBUG_MODE=true go run main.go
加载多个配置文件
1 2 configor.Load(&Config, "application.yml" , "database.json" )
根据环境变量加载配置文件 or 从shell加载配置项
详细可参考 Golang Configor 配置文件工具
热更新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package mainimport ( "fmt" "time" "github.com/jinzhu/configor" ) type Config struct { APPName string `default:"app name"` DB struct { Name string User string `default:"root"` Password string `required:"true" env:"DBPassword"` Port uint `default:"3306"` } Contacts []struct { Name string Email string `required:"true"` } } func main () { var conf = Config{} err := configor.New(&configor.Config{ AutoReload: true , AutoReloadInterval: time.Second, AutoReloadCallback: func (config interface {}) { fmt.Printf("配置文件发生了变更%#v\n" , config) }, }).Load(&conf, "config.yml" ) if err != nil { panic (err) } fmt.Printf("%v \n" , conf) time.Sleep(100000e9 ) }
完整代码
原文链接: https://dashen.tech/2022/04/17/Go几种读取配置文件的方式/
版权声明: 转载请注明出处.