Viper

简介

Viper 是一个 Go 应用的完整配置解决方案,包括微服务的12要素,主要支持一下特性

  • 默认值设置
  • Golang的配置管理库
  • 支持从JSON, TOML, YAML, HCL, envfile , Java 配置文件读取
  • 实时监视和重新读取配置文件
  • 读取环境变量配置
  • 从远处配置系统(etcd or Consul)中读取
  • 从命令行标志读取
  • 从缓冲区读取
  • 显示设置配置

viper读取配置文件的优先级顺序:

  • viper.Set() 所设置的值
  • 命令行 flag
  • 环境变量
  • 配置文件
  • 配置中心etcd/consul
  • 默认值

注意:viper的配置键是不区分大小写的。

安装

go get -u https://github.com/spf13/viper

从配置文件读取值

1
2
3
4
5
6
7
8
viper.SetConfigName("production") // 设置配置文件名
viper.SetConfigType("yaml") // 设置配置文件类型
viper.AddConfigPath("./config") // 设置配置文件路径,可以重复该语法设置多个路径
viper.AddConfigPath(".") // 在当前工作目录寻找配置文件
err := viper.ReadInConfig() // 查找并读取配置文件
if err != nil {
panic(fmt.Errorf("Fatal error config file: %w \n", err))
}

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"datastore.metric.host": "0.0.0.0",
"host": {
"address": "localhost",
"port": [
5799,
6029
]
},
"datastore": {
"metric": {
"host": "127.0.0.1",
"port": 3099
},
"warehouse": {
"host": "198.0.0.1",
"port": 2112
}
}
}
viper.GetString("datastore.warehouse.host") // (returns "198.0.0.1")
viper.GetInt("host.ports.1") // returns 6029
viper.GetString("datastore.metric.host") // 存在值为路径的键将被优先返回returns "0.0.0.0"

设置默认值

1
2
viper.SetDefault("username", "stolen")
viper.SetDefault("city", map[string]string{"country": "China", "Province": "Chengdu"})

写到配置文件

1
2
3
4
viper.WriteConfig()     // 将配置写入到 AddConfigPath 和 SetConfigName 配置的文件中,会覆盖已存在的文件
viper.SafeWriteConfig() // 与 WriteConfig 区别是不会覆盖当前已经存在的文件
viper.WriteConfigAs("/path/to/my/.config") // 覆盖写入制定的文件
viper.SafeWriteConfigAs("/path/to/my/.config") // 不会覆盖的写入制定的文件

监测并热加载配置文件

viper 支持应用程序在运行中实时读取配置文件的能力。确保在调用 WatchConfig() 之前添加所有的configPaths

1
2
3
4
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config file changed:", e.Name)
})
viper.WatchConfig()

从 io.Reader 读取配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
viper.SetConfigType("yaml") // or viper.SetConfigType("YAML")

// any approach to require this configuration into your program.
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") // this would be "steve"

设置字段值

1
2
3
4
5
6
7
8
9
10
viper.Set("Verbose", true) // 如果配置中已经存在该键,将会覆盖以存在键的值
viper.Set("LogFile", LogFile)

viper.RegisterAlias("aliasString", "keyString") // 给键设置一个别名

viper.Set("aliasString", true) // 实际操作的是 keyString 这个键
viper.Set("keyString", true) // 实际操作的是 keyString 这个键

viper.GetBool("aliasString") // true
viper.GetBool("aliasString") // true

读配置字段

1
2
3
4
5
6
7
8
9
10
11
12
13
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函数将返回一个 0 值。为了检查一个给定的键是否存在,已经提供了 IsSet() 方法来检查键是否被设置了。

vipers

viper 是一个不需要配置或初始化就可以开箱即用的工具,因为大部分应用都使用单一的配置中心来管理配置,类似单例。

但如果用户需要使用多个配置中心,可以进行实例化创建不同的 viper,每个 viper 可以读取不同的配置文件,设置不同的参数,像下面代码这样

1
2
3
4
5
6
7
x := viper.New()
y := viper.New()

x.SetDefault("ContentDir", "content")
y.SetDefault("ContentDir", "foobar")

//...