您现在的位置是:网站首页> 编程资料编程资料
golang配置管理神器Viper使用教程_Golang_
2023-05-26
342人已围观
简介 golang配置管理神器Viper使用教程_Golang_
Viper
Viper是适用于Go应用程序的完整配置解决方案。它被设计用于在应用程序中工作,并且可以处理所有类型的配置需求和格式。
鉴于viper库本身的README已经写得十分详细,这里就将其翻译成中文,并在最后附上两个项目中使用viper的示例代码以供参考。
安装
go get github.com/spf13/viper
什么是Viper?
Viper是适用于Go应用程序(包括Twelve-Factor App)的完整配置解决方案。它被设计用于在应用程序中工作,并且可以处理所有类型的配置需求和格式。它支持以下特性:
- 设置默认值
- 从
JSON、TOML、YAML、HCL、envfile和Java properties格式的配置文件读取配置信息 - 实时监控和重新读取配置文件(可选)
- 从环境变量中读取
- 从远程配置系统(etcd或Consul)读取并监控配置变化
- 从命令行参数读取配置
- 从buffer读取配置
- 显式配置值
为什么选择Viper?
在构建现代应用程序时,你无需担心配置文件格式;你想要专注于构建出色的软件。Viper的出现就是为了在这方面帮助你的。
Viper能够为你执行下列操作:
- 查找、加载和反序列化
JSON、TOML、YAML、HCL、INI、envfile和Java properties格式的配置文件。 - 提供一种机制为你的不同配置选项设置默认值。
- 提供一种机制来通过命令行参数覆盖指定选项的值。
- 提供别名系统,以便在不破坏现有代码的情况下轻松重命名参数。
- 当用户提供了与默认值相同的命令行或配置文件时,可以很容易地分辨出它们之间的区别。
Viper会按照下面的优先级。每个项目的优先级都高于它下面的项目:
- 显示调用
Set设置值 - 命令行参数(flag)
- 环境变量
- 配置文件
- key/value存储
- 默认值
重要: 目前Viper配置的键(Key)是大小写不敏感的。目前正在讨论是否将这一选项设为可选。
把值存入Viper
建立默认值
一个好的配置系统应该支持默认值。键不需要默认值,但如果没有通过配置文件、环境变量、远程配置或命令行标志(flag)设置键,则默认值非常有用。
例如:
viper.SetDefault("ContentDir", "content") viper.SetDefault("LayoutDir", "layouts") viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"}) 读取配置文件
Viper需要最少知道在哪里查找配置文件的配置。Viper支持JSON、TOML、YAML、HCL、envfile和Java properties格式的配置文件。Viper可以搜索多个路径,但目前单个Viper实例只支持单个配置文件。Viper不默认任何配置搜索路径,将默认决策留给应用程序。
下面是一个如何使用Viper搜索和读取配置文件的示例。不需要任何特定的路径,但是至少应该提供一个配置文件预期出现的路径。
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)) } 在加载配置文件出错时,你可以像下面这样处理找不到配置文件的特定情况:
if err := viper.ReadInConfig(); err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); ok { // 配置文件未找到错误;如果需要可以忽略 } else { // 配置文件被找到,但产生了另外的错误 } } // 配置文件找到并成功解析 注意[自1.6起]: 你也可以有不带扩展名的文件,并以编程方式指定其格式。对于位于用户$HOME目录中的配置文件没有任何扩展名,如.bashrc。
这里补充两个问题供读者解答并自行验证
当你使用如下方式读取配置时,viper会从./conf目录下查找任何以config为文件名的配置文件,如果同时存在./conf/config.json和./conf/config.yaml两个配置文件的话,viper会从哪个配置文件加载配置呢?
viper.SetConfigName("config") viper.AddConfigPath("./conf") 在上面两个语句下搭配使用viper.SetConfigType("yaml")指定配置文件类型可以实现预期的效果吗?
写入配置文件
从配置文件中读取配置文件是有用的,但是有时你想要存储在运行时所做的所有修改。为此,可以使用下面一组命令,每个命令都有自己的用途:
- WriteConfig - 将当前的
viper配置写入预定义的路径并覆盖(如果存在的话)。如果没有预定义的路径,则报错。 - SafeWriteConfig - 将当前的
viper配置写入预定义的路径。如果没有预定义的路径,则报错。如果存在,将不会覆盖当前的配置文件。 - WriteConfigAs - 将当前的
viper配置写入给定的文件路径。将覆盖给定的文件(如果它存在的话)。 - SafeWriteConfigAs - 将当前的
viper配置写入给定的文件路径。不会覆盖给定的文件(如果它存在的话)。
根据经验,标记为safe的所有方法都不会覆盖任何文件,而是直接创建(如果不存在),而默认行为是创建或截断。
一个小示例:
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) }) 从io.Reader读取配置
Viper预先定义了许多配置源,如文件、环境变量、标志和远程K/V存储,但你不受其约束。你还可以实现自己所需的配置源并将其提供给viper。
viper.SetConfigType("yaml") // 或者 viper.SetConfigType("YAML") // 任何需要将此配置添加到程序中的方法。 var yamlExample = []byte(` Hacker: true name: steve hobbies: - skateboarding - snowboarding - go clothing: jacket: leather trousers: denim age: 35 eyes : brown beard: true `) viper.ReadConfig(bytes.NewBuffer(yamlExample)) viper.Get("name") // 这里会得到 "steve" 覆盖设置
这些可能来自命令行标志,也可能来自你自己的应用程序逻辑。
viper.Set("Verbose", true) viper.Set("LogFile", LogFile) 注册和使用别名
别名允许多个键引用单个值
viper.RegisterAlias("loud", "Verbose") // 注册别名(此处loud和Verbose建立了别名) viper.Set("verbose", true) // 结果与下一行相同 viper.Set("loud", true) // 结果与前一行相同 viper.GetBool("loud") // true viper.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 示例:
SetEnvPrefix("spf") // 将自动转为大写 BindEnv("id") os.Setenv("SPF_ID", "13") // 通常是在应用程序之外完成的 id := Get("id") // 13 使用Flags
Viper 具有绑定到标志的能力。具体来说,Viper支持Cobra库中使用的Pflag。
与BindEnv类似,该值不是在调用绑定方法时设置的,而是在访问该方法时设置的。这意味着你可以根据需要尽早进行绑定,即使在init()函数中也是如此。
对于单个标志,BindPFlag()方法提供此功能。
例如:
相关内容
- zap接收gin框架默认的日志并配置日志归档示例_Golang_
- golang默认Logger日志库在项目中使用Zap日志库_Golang_
- golang gorm实现get请求查询案例测试_Golang_
- golang gorm更新日志执行SQL示例详解_Golang_
- golang gorm开发架构及写插件示例_Golang_
- golang gorm错误处理事务以及日志用法示例_Golang_
- golang gorm的Callbacks事务回滚对象操作示例_Golang_
- Golang协程池gopool设计与实现_Golang_
- golang gorm的预加载及软删硬删的数据操作示例_Golang_
- golang gorm的关系关联实现示例_Golang_
