Viper
Viper 是适用于 Go 应用程序的完整配置解决方案。它被设计用于在应用程序中工作,并且可以处理所有类型的配置需求和格式。
文档
安装
go get github.com/spf13/viper
使用
新建配置文件/config/config.toml
aaa = "111"
bbb = "222"
Viper 只需简单设置就可以读取到配置信息。
//设置文件路径
viper.AddConfigPath("/config")
//设置文件名
viper.SetConfigName("config")
//设置文件类型
viper.SetConfigType("toml")
//读取配置文件
_ = viper.ReadInConfig()
//监控配置文件变动
viper.WatchConfig()
for {
//输出所有配置
fmt.Println(viper.AllSettings())
time.Sleep(time.Second)
}
多配置文件
随着项目开发,配置文件中的信息可能会越来越多,全部集中到一个文件中会变的难以管理。按功能分为不同的配置文件更易于管理,我们来自己实现一个多配置文件的方法。
方法一
使用MergeInConfig()
方法将多个配置文件内容合并到一起。
在新建一个/config/router.toml
配置文件
port = 8000
//设置文件路径
viper.AddConfigPath("/config")
//设置文件名
viper.SetConfigName("config")
//设置文件类型
viper.SetConfigType("toml")
//读取配置文件
_ = viper.ReadInConfig()
//设置第二个配置文件名称
viper.SetConfigName("router")
//读取并合并已有配置
_ = viper.MergeInConfig()
//输出所有配置
fmt.Println(viper.AllSettings())
//map[aaa:111 bbb:222 port:8000]
这种方法存在一个问题,多个配置文件中不能存在相同的 key 值,不然后一个配置文件会覆盖掉前一个配置文件相同 key 的值。
方法二
使用配置文件名作为 key ,其中配置信息作为 value ,这样即使不同文件中存在相同的值也无妨了。
新建一个 config 包对 Viper 配置文件进行处理
/pkg/config/config.go
package config
import (
"github.com/spf13/viper"
"io/ioutil"
"path"
"strings"
)
var cfg *viper.Viper
func Init() {
dirname := "config"
//创建一个新的Viper实例
cfg = viper.New()
viper.AddConfigPath(dirname)
//循环读取路径下的所有配置文件
//将文件名作为key配置信息作为value
//set到创建的cfg实例中
for _, cf := range readConfigFile(dirname) {
viper.SetConfigType(cf["ext"])
viper.SetConfigName(cf["name"])
err := viper.ReadInConfig()
if err != nil {
panic(err)
}
s := viper.AllSettings()
if len(s) > 0 {
cfg.Set(cf["name"], s)
}
}
}
//读取路径下的所有文件
func readConfigFile(dirname string) (configFile []map[string]string) {
dir, err := ioutil.ReadDir(dirname)
if err != nil {
panic(err)
}
for _, fileInfo := range dir {
fileName := fileInfo.Name()
ext := path.Ext(fileName)
configFile = append(configFile, map[string]string{
"name": fileName[0 : len(fileName)-len(ext)],
"ext": strings.Trim(ext, "."),
})
}
return
}
//因为cfg实例设置的是私有变量
//所以要访问Viper的方法需要重新定义一下
func AllSettings() map[string]interface{} {
return cfg.AllSettings()
}
然后在/boot/boot.go
的Init()
方法中调用config.Init()
进行配置的初始化操作。
读取所有配置信息
fmt.Println(config.AllSettings())
//map[config:map[aaa:111 bbb:222] router:map[port:8000]]
监控文件变动
多配置文件方法要实现监控文件的变动,就不能只是简单的添加一个viper.WatchConfig()
方法就可以了,因为我们创建了一个新的 Viper 实例来保存多文件的配置,这个方法并不能影响到这个实例。但我们可以对每一个配置文件进行监控,然后使用viper.OnConfigChange()
方法进行回调处理。
func configChange(v *viper.Viper) {
//监控文件变化
v.WatchConfig()
//文件变化后的回调处理
v.OnConfigChange(func(in fsnotify.Event) {
fileName := filepath.Base(in.Name)
ext := path.Ext(fileName)
name := fileName[0 : len(fileName)-len(ext)]
v.SetConfigType(strings.Trim(ext, "."))
v.SetConfigName(name)
s := v.AllSettings()
if len(s) > 0 {
cfg.Set(name, s)
}
})
}
然后在Init()
方法的 for 循环中,读取完配置信息之后调用configChange(viper.GetViper())
。