GoLang viper 读取配置文件

您所在的位置:网站首页 ifan什么意思 GoLang viper 读取配置文件

GoLang viper 读取配置文件

2024-07-12 15:12| 来源: 网络整理| 查看: 265

Viper配置文件读取Go使用Viper加载配置文件

Github

安装

1go get github.com/spf13/viper 1. 初次使用1234567891011func main(){ var config Config viper.SetConfigName("config") // 设置配置文件名 (不带后缀) viper.AddConfigPath(".") // 第一个搜索路径 err := viper.ReadInConfig() // 读取配置数据 if err != nil { panic(fmt.Errorf("Fatal error config file: %s \n", err)) } viper.Unmarshal(&config) // 将配置信息绑定到结构体上 fmt.Println(config)} 2. 读取配置文件12345678910viper.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))}

加载配置文件出错,处理特定错误

123456789if err := viper.ReadInConfig(); err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); ok { // 配置文件未找到错误;如果需要可以忽略 } else { // 配置文件被找到,但产生了另外的错误 }}// 配置文件找到并成功解析 监控并重新读取配置文件

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

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

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

12345viper.WatchConfig()viper.OnConfigChange(func(e fsnotify.Event) { // 配置文件发生变更之后会调用的回调函数 fmt.Println("Config file changed:", e.Name)}) 从io.Reader读取配置123456789101112131415161718192021viper.SetConfigType("yaml") // 或者 viper.SetConfigType("YAML")// 任何需要将此配置添加到程序中的方法。var yamlExample = []byte(`Hacker: truename: stevehobbies:- skateboarding- snowboarding- goclothing: jacket: leather trousers: denimage: 35eyes : brownbeard: true`)viper.ReadConfig(bytes.NewBuffer(yamlExample))viper.Get("name") // 这里会得到 "steve" 覆盖配置12viper.Set("Verbose", true)viper.Set("LogFile", LogFile) 注册和使用别名1234567viper.RegisterAlias("loud", "Verbose") // 注册别名(此处loud和Verbose建立了别名)viper.Set("verbose", true) // 结果与下一行相同viper.Set("loud", true) // 结果与前一行相同viper.GetBool("loud") // trueviper.GetBool("verbose") // true 使用环境变量

Viper完全支持环境变量。这使Twelve-Factor App开箱即用。有五种方法可以帮助与ENV协作:

AutomaticEnv() BindEnv(string...) : error SetEnvPrefix(string) SetEnvKeyReplacer(string...) *strings.Replacer AllowEmptyEnv(bool)

使用ENV变量时,务必要意识到Viper将ENV变量视为区分大小写。

Viper提供了一种机制来确保ENV变量是惟一的。通过使用SetEnvPrefix,你可以告诉Viper在读取环境变量时使用前缀。BindEnv和AutomaticEnv都将使用这个前缀。

BindEnv使用一个或两个参数。第一个参数是键名称,第二个是环境变量的名称。环境变量的名称区分大小写。如果没有提供ENV变量名,那么Viper将自动假设ENV变量与以下格式匹配:前缀+ “_” +键名全部大写。当你显式提供ENV变量名(第二个参数)时,它 不会 自动添加前缀。例如,如果第二个参数是“id”,Viper将查找环境变量“ID”。

在使用ENV变量时,需要注意的一件重要事情是,每次访问该值时都将读取它。Viper在调用BindEnv时不固定该值。

AutomaticEnv是一个强大的助手,尤其是与SetEnvPrefix结合使用时。调用时,Viper会在发出viper.Get请求时随时检查环境变量。它将应用以下规则。它将检查环境变量的名称是否与键匹配(如果设置了EnvPrefix)。

SetEnvKeyReplacer允许你使用strings.Replacer对象在一定程度上重写 Env 键。如果你希望在Get()调用中使用-或者其他什么符号,但是环境变量里使用_分隔符,那么这个功能是非常有用的。可以在viper_test.go中找到它的使用示例。

或者,你可以使用带有NewWithOptions工厂函数的EnvKeyReplacer。与SetEnvKeyReplacer不同,它接受StringReplacer接口,允许你编写自定义字符串替换逻辑。

默认情况下,空环境变量被认为是未设置的,并将返回到下一个配置源。若要将空环境变量视为已设置,请使用AllowEmptyEnv方法。

Env 示例:123456SetEnvPrefix("spf") // 将自动转为大写BindEnv("id")os.Setenv("SPF_ID", "13") // 通常是在应用程序之外完成的id := Get("id") // 13 3. 写入配置文件

从配置文件中读取配置文件是有用的,但是有时你想要存储在运行时所做的所有修改。为此,可以使用下面一组命令,每个命令都有自己的用途:

WriteConfig - 将当前的viper配置写入预定义的路径并覆盖(如果存在的话)。如果没有预定义的路径,则报错。 SafeWriteConfig - 将当前的viper配置写入预定义的路径。如果没有预定义的路径,则报错。如果存在,将不会覆盖当前的配置文件。 WriteConfigAs - 将当前的viper配置写入给定的文件路径。将覆盖给定的文件(如果它存在的话)。 SafeWriteConfigAs - 将当前的viper配置写入给定的文件路径。不会覆盖给定的文件(如果它存在的话)。

根据经验,标记为safe的所有方法都不会覆盖任何文件,而是直接创建(如果不存在),而默认行为是创建或截断。

12345viper.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") 4. 读取远程配置

在Viper中启用远程支持,需要在代码中匿名导入viper/remote这个包。

1import _ "github.com/spf13/viper/remote"

Viper将读取从Key/Value存储(例如etcd或Consul)中的路径检索到的配置字符串(如JSON、TOML、YAML、HCL、envfile和Java properties格式)。这些值的优先级高于默认值,但是会被从磁盘、flag或环境变量检索到的配置值覆盖。(译注:也就是说Viper加载配置值的优先级为:磁盘上的配置文件>命令行标志位>环境变量>远程Key/Value存储>默认值。)

Viper使用crypt从K/V存储中检索配置,这意味着如果你有正确的gpg密匙,你可以将配置值加密存储并自动解密。加密是可选的。

你可以将远程配置与本地配置结合使用,也可以独立使用。

crypt有一个命令行助手,你可以使用它将配置放入K/V存储中。crypt默认使用在http://127.0.0.1:4001的etcd。

12$ go get github.com/bketelsen/crypt/bin/crypt$ crypt set -plaintext /config/hugo.json /Users/hugo/settings/config.json

确认值已经设置:

1$ crypt get -plaintext /config/hugo.json

有关如何设置加密值或如何使用Consul的示例,请参见crypt文档。

etcd123viper.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 存储:

1234{ "port": 8080, "hostname": "liwenzhou.com"} 123456viper.AddRemoteProvider("consul", "localhost:8500", "MY_CONSUL_KEY")viper.SetConfigType("json") // 需要显示设置成jsonerr := viper.ReadRemoteConfig()fmt.Println(viper.Get("port")) // 8080fmt.Println(viper.Get("hostname")) // liwenzhou.com Firestore123viper.AddRemoteProvider("firestore", "google-cloud-project-id", "collection/document")viper.SetConfigType("json") // 配置的格式: "json", "toml", "yaml", "yml"err := viper.ReadRemoteConfig()

当然,你也可以使用SecureRemoteProvider

远程k/v存储-加密123viper.AddSecureRemoteProvider("etcd","http://127.0.0.1:4001","/config/hugo.json","/etc/secrets/mykeyring.gpg")viper.SetConfigType("json") // 因为在字节流中没有文件扩展名,所以这里需要设置下类型。支持的扩展名有 "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv"err := viper.ReadRemoteConfig() 监控etcd中的更改-未加密12345678910111213141516171819202122232425262728// 或者你可以创建一个新的viper实例var runtime_viper = viper.New()runtime_viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/hugo.yml")runtime_viper.SetConfigType("yaml") // 因为在字节流中没有文件扩展名,所以这里需要设置下类型。支持的扩展名有 "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv"// 第一次从远程读取配置err := runtime_viper.ReadRemoteConfig()// 反序列化runtime_viper.Unmarshal(&runtime_conf)// 开启一个单独的goroutine一直监控远端的变更go func(){ for { time.Sleep(time.Second * 5) // 每次请求后延迟一下 // 目前只测试了etcd支持 err := runtime_viper.WatchRemoteConfig() if err != nil { log.Errorf("unable to read remote config: %v", err) continue } // 将新配置反序列化到我们运行时的配置结构体中。你还可以借助channel实现一个通知系统更改的信号 runtime_viper.Unmarshal(&runtime_conf) }}() 5. 从Viper中获取值

在Viper中,有几种方法可以根据值的类型获取值。存在以下功能和方法:

Get(key string) : interface{} GetBool(key string) : bool GetFloat64(key string) : float64 GetInt(key string) : int GetIntSlice(key string) : []int GetString(key string) : string GetStringMap(key string) : map[string]interface{} GetStringMapString(key string) : map[string]string GetStringSlice(key string) : []string GetTime(key string) : time.Time GetDuration(key string) : time.Duration IsSet(key string) : bool AllSettings() : map[string]interface{}

需要认识到的一件重要事情是,每一个Get方法在找不到值的时候都会返回零值。为了检查给定的键是否存在,提供了IsSet()方法。

1234viper.GetString("logfile") // 不区分大小写的设置和获取if viper.GetBool("verbose") { fmt.Println("verbose enabled")} 访问嵌套的键

访问器方法也接受深度嵌套键的格式化路径。例如,如果加载下面的JSON文件:

12345678910111213141516{ "host": { "address": "localhost", "port": 5799 }, "datastore": { "metric": { "host": "127.0.0.1", "port": 3099 }, "warehouse": { "host": "198.0.0.1", "port": 2112 } }}

Viper可以通过传入.分隔的路径来访问嵌套字段:

1GetString("datastore.metric.host") // (返回 "127.0.0.1") 提取子树

从Viper中提取子树。

例如,viper实例现在代表了以下配置:

1234567app: cache1: max-items: 100 item-size: 64 cache2: max-items: 200 item-size: 80

执行后:

1subv := viper.Sub("app.cache1")

subv现在就代表:

12max-items: 100item-size: 64

假设我们现在有这么一个函数:

1func NewCache(cfg *Viper) *Cache {...}

它基于subv格式的配置信息创建缓存。现在,可以轻松地分别创建这两个缓存,如下所示:

12345cfg1 := viper.Sub("app.cache1")cache1 := NewCache(cfg1)cfg2 := viper.Sub("app.cache2")cache2 := NewCache(cfg2)


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3