go语言中读取配置文件的方法总结
使用viper管理配置
- 支持多种配置文件格式,包括 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() 的优先级高于 配置文件
package main import ( "fmt" "github.com/spf13/viper" ) func main() { loadConfig() } func loadConfig() { configVar := "shuang-config.yaml" configVar = "" // 这行如果注释掉,则从指定的configVar读取配置文件;否则就各种条件去找了 viper.Set("Global.Source", "优先级最高") if configVar != "" { // SetConfigFile 显式定义配置文件的路径、名称和扩展名。 // Viper 将使用它而不检查任何配置路径。 viper.SetConfigFile(configVar) } else { // 如果没有显式指定配置文件,则 // 会去下面的路径里找文件名`cui-config`的文件 name of config file (without extension) // 按照 []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}的顺序(居然还支持Java用的properties) 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")) }
输出:
到底用的是哪个配置文件: '/Users/fliter/config-demo/cui-config.yaml'
Global.Source这个字段的值为: '优先级最高'
验证一下 环境变量 的优先级高于 配置文件
package main import ( "fmt" "github.com/spf13/viper" ) func main() { loadConfig() } func loadConfig() { configVar := "shuang-config.yaml" configVar = "" // 这行如果注释掉,则从指定的configVar读取配置文件;否则就各种条件去找了 viper.Set("Global.Source", "优先级最高") viper.AutomaticEnv() if configVar != "" { // SetConfigFile 显式定义配置文件的路径、名称和扩展名。 // Viper 将使用它而不检查任何配置路径。 viper.SetConfigFile(configVar) } else { // 如果没有显式指定配置文件,则 // 会去下面的路径里找文件名`cui-config`的文件 name of config file (without extension) // 按照 []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}的顺序(居然还支持Java用的properties) 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也是同一作者的作品
验证一下 默认值的优先级低于 配置文件
package main import ( "fmt" "github.com/spf13/viper" ) func main() { loadConfig() } func loadConfig() { configVar := "shuang-config.yaml" configVar = "" // 这行如果注释掉,则从指定的configVar读取配置文件;否则就各种条件去找了 //viper.Set("Global.Source", "优先级最高") viper.AutomaticEnv() viper.SetDefault("Global.Source", "优先级最低") if configVar != "" { // SetConfigFile 显式定义配置文件的路径、名称和扩展名。 // Viper 将使用它而不检查任何配置路径。 viper.SetConfigFile(configVar) } else { // 如果没有显式指定配置文件,则 // 会去下面的路径里找文件名`cui-config`的文件 name of config file (without extension) // 按照 []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}的顺序(居然还支持Java用的properties) 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机制(配置更新后 热加载)
该机制可以监听配置文件的修改, 这样就实现了热加载,修改配置后,无需重启服务
- 对于本地文件,是通过
fsnotify
实现的,然后通过一个回调函数去通知应用来reload; - 对于Remote KV Store,目前只支持etcd,做法比较ugly,(5秒钟)轮询一次 而不是watch api
package main import ( "fmt" "time" "github.com/fsnotify/fsnotify" "github.com/spf13/viper" ) func main() { loadConfig() } func loadConfig() { configVar := "shuang-config.yaml" configVar = "" // 这行如果注释掉,则从指定的configVar读取配置文件;否则就各种条件去找了 if configVar != "" { // SetConfigFile 显式定义配置文件的路径、名称和扩展名。 // Viper 将使用它而不检查任何配置路径。 viper.SetConfigFile(configVar) } else { // 如果没有显式指定配置文件,则 // 会去下面的路径里找文件名`cui-config`的文件 name of config file (without extension) // 按照 []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}的顺序(居然还支持Java用的properties) 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) }
configor
Configor: 一个Golang配置工具,支持YAML,JSON,TOML,Shell环境,支持热加载
出自jinzhu大佬
package main import ( "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") // err := configor.New(&configor.Config{Debug: true}).Load(&conf, "config.yml") // 测试模式,也可以通过环境变量开启测试模式(CONFIGOR_DEBUG_MODE=true go run main.go ),这样就无需修改代码 //err := configor.New(&configor.Config{Verbose: true}).Load(&conf, "config.yml") // 模式,也可以通过环境变量开启详细模式(CONFIGOR_VERBOSE_MODE=true go run main.go ),这样就无需修改代码 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
加载多个配置文件
// application.yml 的优先级 大于 database.json, 排在前面的配置文件优先级大于排在后的的配置 configor.Load(&Config, "application.yml", "database.json")
根据环境变量加载配置文件 or 从shell加载配置项
详细可参考 Golang Configor 配置文件工具
热更新
package main import ( "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{} // reload模式,可实现热加载 err := configor.New(&configor.Config{ AutoReload: true, AutoReloadInterval: time.Second, AutoReloadCallback: func(config interface{}) { // config发生变化后出发什么操作 fmt.Printf("配置文件发生了变更%#v\n", config) }, }).Load(&conf, "config.yml") // 无reload模式 //err := configor.Load(&conf, "config.yml") // err := configor.New(&configor.Config{Debug: true}).Load(&conf, "config.yml") // 测试模式,也可以通过环境变量开启测试模式(CONFIGOR_DEBUG_MODE=true go run main.go ),这样就无需修改代码 //err := configor.New(&configor.Config{Verbose: true}).Load(&conf, "config.yml") // 模式,也可以通过环境变量开启详细模式(CONFIGOR_VERBOSE_MODE=true go run main.go ),这样就无需修改代码 if err != nil { panic(err) } fmt.Printf("%v \n", conf) time.Sleep(100000e9) }
到此这篇关于go语言中读取配置文件的方法总结的文章就介绍到这了,更多相关go读取配置文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Windows环境下vscode-go安装笔记(不支持32位)
这篇文章主要介绍了Windows环境下vscode-go安装笔记(不支持32位),需要的朋友可以参考下2017-02-02
最新评论