配置文件管理是我们在开发过程中必须重视的一个环节。今天小编给大家推荐一个功能丰富的管理配置文件的类库 viper(蝮蛇),这个名字听上去就很凶,该类库的作者还有一个类库叫Cobra(眼镜蛇)。这两个包可以独立使用,也可以组合使用。当然本文的重点是viper,接下来赶紧跟随小编的脚步来体验一下这个强大的类库吧。
特性
- 支持设置默认值
- 支持读取JSON TOML YAML HCL 和Java属性配置文件.(官方说可以解析所有类型的配置文件 can handle all types of configuration needs and formats.)
- 可以监控配置文件的变动,并实时读取配置文件内容
- 支持读取环境变量
- 支持从远端配置系统读取信息(如:etcd、consul),并且可以监听器变化
- 支持读取命令行的flag标识作为配置信息
- 可以从缓冲区中读取
- 支持设置显示的值
配置加载顺序
- 设置显示调用(explicit call to Set)
- 命令行标志(flag)
- 环境变量(env)
- 配置文件(config)
- 远程键/值存储(key/value store)
- 默认值(default)
基本用法
我写了一个简单的demo,目录结构如下
├── config
│ └── env.yml
├── go.mod
├── go.sum
└── main.go
一、从单个配置文件读取配置
package main
import (
"fmt"
"github.com/spf13/viper"
)
// 定义Mysql配置对应的结构体
type MysqlConf struct {
Host string
Port int
Username string
Password string
Database string
Charset string
DBPrefix string
Collection string
ConnTimeout int
MaxOpenConns int
MaxIdleConns int
ConnMaxLifetime int
LogMode bool
}
func main() {
// 设置配置文件的路径
viper.AddConfigPath("./config")
// 设置配置文件名称
viper.SetConfigName("env.yml")
// 以上2步可用 viper.SetConfigFile("./config/env.yml")代替,直接指定文件的相对路径
// 设置配置文件类型
viper.SetConfigType("yaml")
// 加载配置文件内容
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// 配置文件未找到
panic("配置文件未找到")
} else {
// Config file was found but another error was produced
panic(fmt.Errorf("读取配置文件失败: %s \n", err.Error()))
}
}
// 读取文件配置项
domain := viper.GetString("Domain") // 读取Domain节点
serverPort := viper.GetInt("ServerPort") // 读取ServerPort节点并且返回值未int类型
mysqlPort := viper.GetInt("MySQL.Port") // 读取MySQL节点下的Port节点 . 符号隔开层级
fmt.Println(domain, serverPort, mysqlPort)
// 将整个MySQL节点下的内容读取到结构体中
var myCnf MysqlConf
if err := viper.UnmarshalKey("MySQL", &myCnf); err != nil {
fmt.Println("Read MySQL config error" + err.Error())
}
fmt.Printf("%+v \n", myCnf)
}
读取文件内容的方法如下
- 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{}
二、从多配置文件读取
我现在在config目录下加了一个redis.yml配置文件,内容如下
Host: "127.0.0.1"
Port: 6379
Password: ""
Database: 0 # 默认:0
ConnTimeout: 10 # 连接超时时间「单位:秒」
ReadTimeout: 10 # 读取超时时间「单位:秒」
WriteTimeout: 10 # 写入超时时间「单位:秒」
MaxActiveConn: 20 # 最大活跃连接数
MaxIdleConn: 10 # 最大空闲连接数
IdleTimeout: 3600 # 连接空闲的超时时间「单位:秒;0:不限」
MaxConnLifetime: 0 # 连接能够被复用的最大生命周期「单位:秒;0:不限」
TestOnBorrow: 60 # 连接健康检查周期「单位:秒」
PoolWait: false # 连接池无连接时,是否等待连接回池
分开读取配置信息
// 读取env.yml的配置信息
envYaml := viper.New()
envYaml.SetConfigFile("./config/env.yml")
envYaml.SetConfigType("yaml")
if err := envYaml.ReadInConfig(); err != nil {
panic("Read env config file error:" + err.Error())
}
fmt.Println(envYaml.GetString("Domain")) // 127.0.0.1
// 读取redis.yml的配置信息
redisYaml := viper.New()
redisYaml.SetConfigFile("./config/redis.yml")
redisYaml.SetConfigType("yaml")
if err := redisYaml.ReadInConfig(); err != nil {
panic("Read env config file error:" + err.Error())
}
fmt.Println(redisYaml.GetInt("Port")) // 6379
小编会在 一文中继续讲解如何使用viper将配置写入文件以及配置文件的监听