Viper 大中型项目配置解析神器
1.简介
1.1 功能
- 支持JSON,TOML,YAML,Java propertoes等多种不同类型配置文件。
- 支持配置key值默认值,且不区分大小写
- 读取系统环境变量等方式
1.2 配置优先级
viper支持从多个数据源读取配置值,因此当同一个配置key在多个数据源有值时,需要一定的优先级:
- Set:使用Set函数设置值
- flag:命令行参数
- env:环境变量
- config:配置文件
- key/value store:k-v存储系统,eg:ectd
- default:默认值
1.3 安装viper
go get github.com/spf13/viper
import "github.com/spf13/viper"
1.4 支持格式
json | toml | yaml | yml | properties | props |
---|---|---|---|---|---|
prop | hcl | tfvars | dontenv | env | ini |
2 viper 使用
2.1 默认值和配置文件读取
func main() {
v := viper.New()
// 设置默认值
v.SetDefault("key1", "value1")
fmt.Printf("默认值 key1= %s \n", v.Get("key1"))
// 读取配置文件
v.SetConfigFile("./config.yml")
v.ReadInConfig()
fmt.Printf("读取配置文件 key2= %s \n", v.Get("key2"))
fmt.Printf("读取配置文件 key1= %s \n", v.Get("key1"))
}
2.2 多路径查找
viper.SetConfigName("config") // 配置文件名,不需要后缀名
viper.SetConfigType("yml") // 配置文件格式
viper.AddConfigPath("/etc/appname/") // 查找配置文件的路径
viper.AddConfigPath("$HOME/.appname") // 查找配置文件的路径
viper.AddConfigPath(".") // 查找配置文件的路径
err := viper.ReadInConfig() // 查找并读取配置文件
if err != nil { // 处理错误
if_, ok := err.(viper.ConfigFileNotFoundError); ok { // 如果错误是因为找不到文件的报错
}else{
panic(fmt.Errorf("Fatal error config file: %w \n", err))
}
}
2.3 写配置文件
// 写配置文件
v.AddConfigPath(".")
v.SetConfigName("config")
// WriteConfig 将配置写入预先设置好路径的配置文件中,如果配置文件存在,则覆盖,如果没有,则创建。
v.Set("key3", "value3")
v.WriteConfig()
// SafeWriteConfig 与WriteConfig函数唯一的不同是如果配置文件存在,则会返回一个错误。
v.Set("key3", "value3")
if err := v.SafeWriteConfig(); err != nil {
fmt.Println(err)
}
// WriteConfigAs 与WriteConfig函数的不同是需要传入配置文件保存路径,viper会根据文件后缀判断写入格式。
v.Set("key4", "value4")
v.WriteConfigAs("config.yml")
// SafeWriteConfigAs 与WriteConfigAs的唯一不同是如果配置文件存在,则返回一个错误。
v.Set("key5", "value5")
if err := v.SafeWriteConfigAs("config.yml"); err != nil {
fmt.Println(err)
}
config.yml
将v.SafeWriteConfigAs("config.yml")
改为yaml文件
config.yaml
2.4 监控并重新读取配置文件
// 在监控之前要添加要监控的文件或路径
v.OnConfigChange(func(in fsnotify.Event) {
fmt.Println("config file changed:", in.Name)
})
fmt.Printf("读取配置文件 key4= %s \n", v.Get("key4"))
v.WatchConfig()
// 趁这期间修改配置文件
for i := 0; i < 10; i++ {
time.Sleep(time.Second)
}
fmt.Printf("读取配置文件 key4= %s \n", v.Get("key4"))
读取配置文件 key4= value5
config file changed: config.yml
config file changed: config.yml
读取配置文件 key4= value4
2.5 注册别名
viper.RegisterAlias("key1","key")
之后可以直接操作别名,修改会作用到原本的配置项上。
3 访问配置
{
"mysql":{
"db":"test"
},
"host":{
"address":"localhost"
"ports":[
"8080",
"8081"
]
}
}
直接访问:
viper.Get("mysql.db")
viper.GetString("user.db")
viper.Get("host.address")//输出:localhost
viper.Get("host.posts.1")//输出: 8081
分级读取
hostViper := viper.Sub("host")
fmt.Println(hostViper.Get("address"))
fmt.Println(hostViper.Get("posts.1"))
访问函数:
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
3.1 序列化
config.yaml
host: localhost
username: test
password: test
port: 3306
charset: utf8
dbName: test
type MySQL struct {
Host string
DbName string
Port string
Username string
Password string
Charset string
}
func main() {
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.ReadInConfig()
var mysql MySQL
viper.Unmarshal(&mysql)//序列化
fmt.Println(mysql.Username)
fmt.Println(mysql.Host)
}
// console
test
localhost
多层级配置
mysql:
host: localhost
username: test
password: test
port: 3306
charset: utf8
dbName: test
redis:
host: localhost
port: 6379
type MySQL struct {
Host string
DbName string
Username string
Password string
Charset string
}
type Redis struct {
Host string
Port string
}
type Config struct {
MySQL MySQL
Redis Redis
}
func main() {
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.ReadInConfig()
var config Config
viper.Unmarshal(&config)
fmt.Println(config.MySQL.Username)
fmt.Println(config.Redis.Host)
}
3.2 查看key是否存在
if viper.IsSet("user"){
fmt.Println("key user is not exists")
}
3.3 打印所有配置
m := viper.AllSettings()
fmt.Println(m)
参考链接: