go中的配置解析库viper
Viper是适用于Go应用程序的完整配置解决方案,可以处理几乎所有类型的配置需求和格式
Viper支持多种格式的配置文件,如果没有设置配置文件的类型或后缀,会自动按指定顺序去尝试
"json", "toml", "yaml(yml)","properties(props/prop)", "hcl", "dotenv(env)", "ini"
安装:go get github.com/spf13/viper
引入:import "github.com/spf13/viper"
单例和多例
viper包支持的所有功能都被镜像为viper实例的方法
Viper开箱即用,不需要初始化即可使用,类似于单例模式
也可以创建多个不同的Viper实例,每个都有不同的配置
new_viper := viper.New():创建新的Viper实例
配置信息:
方法一:
viper.SetConfigName(Name string) :设置配置文件名(不含路径和后缀),如果有后缀会认为是文件名的一部分,默认值"config"
viper.SetConfigType(Type string) :设置配置文件类型,可选值json、yaml、ini、toml、hcl、env、properties
yaml:使用缩进级别来进行层次分割,语法类似于json,但字段名无需使用双引号,且最外层无大括号
toml:类似于ini,但是可以使用单引号或双引号来表示字符串以区分数字和字符串
字符串值必须使用单引号或双引号括起来
key也需要使用单引号或双引号括起来,为了简化可以省略,当key中存在空格或点等有歧义的字符时不能省略
hcl:
env:类似于环境变量,所有key转换为大写,点转换为下划线
viper.AddConfigPath(Path string) :设置配置文件搜索目录,可以多次使用该方法以设置多个搜索目录
方法二:
viper.SetConfigFile(conf_file string):指定配置文件的完整路径和名称
如果含有viper.SetConfigType()和viper.AddConfigPath(),会忽略viper.SetConfigFile()方法
读取配置文件
viper.ReadInConfig() err :读取配置信息中的配置文件
读取环境变量
viper.AutomaticEnv() :使用该方法后可以读取环境变量中的值
viper.SetEnvPrefix(pre string) :环境变量的前缀,获取环境变量时会自动添加该前缀
viper.BindEnv(key string, env_key string):绑定一个环境变量到指定的key键
当仅提供一个参数时,默认env_key=key,及此参数既是键名又是环境变量名
viper.BindEnv("mygopath","GOPATH")
viper.BindEnv("gopath")
使用viper.BindEnv仅绑定指定的环境变量,使用AutomaticEnv()方法相当于一次性绑定所有环境变量
viper.AllowEmptyEnv(bool):获取值时是否允许空值,默认一个环境变量的值为空被认为是未设置的,会继续向下寻找
读取命令行
需要引入新的包"flag"和"pflag"
import (
"flag"
"github.com/spf13/pflag"
)
设置命令行的接收参数:
flag.Int(name string, val int, msg string):将接受的值转换为int类型,msg是错误提示信息
flag.String(name string, val string, msg string):将所有的接收值都作为字符串
绑定和添加命令行解析
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
viper.BindPFlags(pflag.CommandLine)
传入格式"--name=val"或"--name val"
设置配置项默认值
viper.SetDefault(key string, value interface{}):设置某个配置项的默认值,key为字符串格式,节点和配置项之间使用点(.)连接
设置配置项的值
viper.Set(key string, value interface{})
读取配置项的值
IsSet(key string) :判断某个键是否存在,返回bool
viper.Get(key string) interface{}
获取配置项的值的顺序:
调用Set()方法设置的值
命令行选项
环境变量
配置文件中的值
默认值
由于Get()方法返回的是一个interface{}的值,使用起来有所不便
GetType系列方法可以返回指定类型的值,Type可以为
Bool
Float64
Int、IntSlice
String、StringSlice
StringMap、StringMapString
Time
Duration
Duration表示time.Duration类型,只要是time.ParseDuration接受的格式都可以,例如3s、2min、1min30s等,返回用纳秒表示的数字
如果读取的配置项不存在,返回对应类型的零值
AllSettings()方法以map[string]interface{}返回所有设置
key中的点(.)和设定的值在不同配置类型文件中的表现
env文件没有节点的概念,会将点转换为下划线,并将所有字符字符转换为大写
只含一个点
如key为"mysql.ip"
除env外均能设置正确的节点和节点下的配置项
节点不存在会创建节点,配置项不存在会创建配置项
配置项存在会修改配置项的值
含2个以上点
如key为"mysql.host.name"
hcl、json、yaml会正常创建多个子节点
ini、toml只会创建一层节点,最后一个点后面为选项,之前部分整体为节点名
如示例中会创建[mysql.host]节点
值的类型
区分字符串和数字
hlc、json、toml文件会为字符串添加上双引号以区分字符串和整数/浮点数
env、ini、yaml文件不会为字符串添加区分标识
toml中多行字符串用三双引号表示
ini文件仅支持数字和字符串,其余格式的值均无法保存,保存文件时保存为空字符串
当值为数组或切片时:除ini文件之外均可正常保存
当值为struct时:
仅env可以保存数据
hcl、json、yaml保存值为一对大括号:"{}"
toml仅创建节点,不创建配置项
当值为map时:
env文件会以"map[key1:val1 key2:val2...]"的形式保存
hcl、json、toml、yaml会便利map中的键,并依次创建键的配置项
需要注意的是如果key中存在点,会整体作为节点的名称而不是继续创建节点
实时监控
viper.WatchConfig():该方法使用以后会自动监听配置修改。如果有修改重新加载配置
viper还提供了监听配置修改的回调函数
import "github.com/fsnotify/fsnotify"
viper.OnConfigChange(func(e fsnotify.Event) {})
fsnotify.Event对象包含两个字段
Name:string,表示发生变化的文件或目录名
Op :uint32,表示具体的变化类型,返回16进制数字(0x前缀)
String()方法可以转换为字符串
"CREATE"、"WRITE"、"REMOVE"、"RENAME"、"CHMOD"
注册和使用别名
viper.RegisterAlias(alias_name string, key string):为key注册一个alias_name别名,后期Set和Get使用原名称和别名效果相同
节点树
viper.Sub(jiedian string) :返回类型为"&viper.Viper"的指定节点的节点树
写入配置文件
从配置文件中读取配置文件是有用的,但是有时你想要存储在运行时所做的所有修改。为此,可以使用下面一组命令,每个命令都有自己的用途:
WriteConfig():将当前的 viper 配置写到预定义路径,如果没有预定义路径,返回错误。将会覆盖当前配置;
SafeWriteConfig():与上面功能一样,但是如果配置文件存在,则不覆盖;
WriteConfigAs(file string):保存配置到指定路径,如果文件存在,则覆盖;
SafeWriteConfig(file string):与上面功能一样,但是入股配置文件存在,则不覆盖。