Vipper配置解析库
Vipper
vipper 是适用于 Go 应用程序的完整配置解析工具.他被设计用于在应用程序中工作.
鉴于 viper 库本身的 README 已经写得十分详细,这里就将其翻译成中文,并在最后附上两个项目中使用 viper 的示例代码以供参考。
安装
1 | go get github.com/spf13/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)是大小写不敏感的。目前正在讨论是否将这一选项设为可选。
建立默认值
一个好的配置系统应该支持默认值。键不需要默认值,但如果没有通过配置文件、环境变量、远程配置或命令行标志(flag)设置键,则默认值非常有用。
例如:
1 | viper.SetDefault("ContentDir", "content") |
读取配置文件
Viper 需要最少知道在哪里查找配置文件的配置。Viper 支持 JSON、TOML、YAML、HCL、envfile 和 Java properties 格式的配置文件。Viper 可以搜索多个路径,但目前单个 Viper 实例只支持单个配置文件。Viper 不默认任何配置搜索路径,将默认决策留给应用程序。
下面是一个如何使用 Viper 搜索和读取配置文件的示例。不需要任何特定的路径,但是至少应该提供一个配置文件预期出现的路径。
1 | viper.SetConfigFile("./config.yaml") // 指定配置文件路径 |
在加载配置文件出错时,你可以像下面这样处理找不到配置文件的特定情况:
1 | if err := viper.ReadInConfig(); err != nil { |
写入配置文件
从配置文件中读取配置文件是有用的,但是有时你想要存储在运行时所做的所有修改。为此,可以使用下面一组命令,每个命令都有自己的用途:
- WriteConfig - 将当前的
viper配置写入预定义的路径并覆盖(如果存在的话)。如果没有预定义的路径,则报错。 - SafeWriteConfig - 将当前的
viper配置写入预定义的路径。如果没有预定义的路径,则报错。如果存在,将不会覆盖当前的配置文件。 - WriteConfigAs - 将当前的
viper配置写入给定的文件路径。将覆盖给定的文件(如果它存在的话)。 - SafeWriteConfigAs - 将当前的
viper配置写入给定的文件路径。不会覆盖给定的文件(如果它存在的话)。
根据经验,标记为safe的所有方法都不会覆盖任何文件,而是直接创建(如果不存在),而默认行为是创建或截断。
一个小示例:
1 | viper.WriteConfig() // 将当前配置写入“viper.AddConfigPath()”和“viper.SetConfigName”设置的预定义路径 |
监控并重新读取配置文件
Viper 支持在运行时实时读取配置文件的功能。
需要重新启动服务器以使配置生效的日子已经一去不复返了,viper驱动的应用程序可以在运行时读取配置文件的更新,而不会错过任何消息。
只需告诉viper实例watchConfig。可选地,你可以为Viper提供一个回调函数,以便在每次发生更改时运行。
确保在调用 WatchConfig() 之前添加了所有的配置路径。
1 | viper.WatchConfig() |
从 io.Reader 读配置
Viper 预先定义了许多配置源,如文件、环境变量、标志和远程 K/V 存储,但你不受其约束。你还可以实现自己所需的配置源并将其提供给 viper。
1 | viper.SetConfigType("yaml") // 或者 viper.SetConfigType("YAML") |
从 Viper 获取值
在 Viper 中,有几种方法可以根据值的类型获取值。存在以下功能和方法:
Get(key string) : interface{}GetBool(key string) : boolGetFloat64(key string) : float64GetInt(key string) : intGetIntSlice(key string) : []intGetString(key string) : stringGetStringMap(key string) : map[string]interface{}GetStringMapString(key string) : map[string]stringGetStringSlice(key string) : []stringGetTime(key string) : time.TimeGetDuration(key string) : time.DurationIsSet(key string) : boolAllSettings() : map[string]interface{}
需要认识到的一件重要事情是,每一个Get方法在找不到值的时候都会返回零值。为了检查给定的键是否存在,提供了IsSet()方法。
例如:
1 | viper.GetString("logfile") // 不区分大小写的设置和获取 |
反序列化
你还可以选择将所有或特定的值解析到结构体、map 等。
有两种方法可以做到这一点:
Unmarshal(rawVal interface{}) : errorUnmarshalKey(key string, rawVal interface{}) : error
举个例子:
1 | type config struct { |
如果你想要解析那些键本身就包含 . (默认的键分隔符)的配置,你需要修改分隔符:
1 | v := viper.NewWithOptions(viper.KeyDelimiter("::")) |
Viper 还支持解析到嵌入的结构体:
1 | /* |
序列化成字符串
你可能需要将 viper 中保存的所有设置序列化到一个字符串中,而不是将它们写入到一个文件中。你可以将自己喜欢的格式的序列化器与 AllSettings() 返回的配置一起使用。
1 |
|
项目实例记录
1 | package core |
