1. 简介

github仓库地址:https://github.com/spf13/viper

文档地址:https://pkg.go.dev/github.com/spf13/viper

viper 是 Go 语言的配置文件管理库,支持 JSON、YAML、TOML 等多种格式的配置文件,可以设置监听配置文件的修改自动加载新配置。

2. 使用

2.1 安装

使用 go get 将 viper 包下载到 GOPATH 指定的目录下。

go get github.com/spf13/viper

2.2 读取配置文件

设置默认值,可以在读取配置文件前设置一些默认的配置。

viper.SetDefault("ContentDir", "content")
viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})

先设置配置文件的名称和文件类型,然后添加配置文件搜索路径,可以添加多个。然后就可以读取配置文件了。

viper.SetConfigName("config")                // 配置文件名称
viper.SetConfigType("yaml")                  // 配置文件类型
viper.AddConfigPath("$HOME")                 // 添加配置文件搜索路径
viper.AddConfigPath("etc")                   // 添加配置文件搜索路径
if err := viper.ReadInConfig(); err != nil { // 读取配置
	if _, ok := err.(viper.ConfigFileNotFoundError); ok {
		panic(fmt.Errorf("config file not found"))
	}
	panic(fmt.Errorf("ReadInConfig fail: %w", err))
}

也可以将内存中的配置修改后写入配置文件,写入时会将设置的默认值也一并写入。

viper.WriteConfig()                         // 将配置写入搜索到的配置文件
viper.SafeWriteConfig()                     // 仅当文件不存在时,将配置写入搜索到的配置文件
viper.WriteConfigAs("etc/config1.yaml")     // 将配置文件写入指定文件
viper.SafeWriteConfigAs("etc/config1.yaml") // 仅当文件不存在时,将配置文件写入指定文件

以上设置和读取是将配置文件读取到了 viper 默认的一个全局的对象中,对于需要读取多个配置文件的场景,可以为每个配置创建一个 viper.Viper 对象。

x := viper.New()
y := viper.New()
x.SetDefault("ContentDir", "content")
y.SetDefault("ContentDir", "foobar")

2.3 监听配置文件

viper 支持监听配置文件,当配置文件发生改动时触发操作,并会重新读取配置。

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

2.4 读写配置

对于根目录下的配置 key,直接使用 key 名称,如 mysql。对于数组和映射表,使用数字和子结构的名称的多层结构,如 mysql.0.port。

主动设置配置,可能是来自于命令行参数或是程序的逻辑。

viper.Set("Verbose", true)
viper.Set("LogFile", LogFile)

// Set 设置配置
func Set(key string, value any)

以三种最常用的配置文件类型为例子:

JSON

{
  "env": "prod",
  "mysql": [
    {
      "host": "127.0.0.1",
      "port": 3306
    }
  ]
}

YAML

env: prod
mysql:
  - host: 127.0.0.1
    port: 3306

TOML

env = "prod"
[[mysql]]
host = "127.0.0.1"
port = 3306

读取配置,有多个方法可以读取不同类型的配置,如果读取不到或者类型不匹配则返回零值。

设置和读取都是不区分大小写的。

env := viper.GetString("env")
mysqlPort := viper.GetInt("mysql.0.port")

// Get 读取配置
func Get(key string) any
func GetBool(key string) bool
func GetInt(key string) int
func GetInt64(key string) int64
func GetIntSlice(key string) []int
func GetFloat64(key string) float64
func GetString(key string) string
func GetStringSlice(key string) []string
func GetStringMap(key string) map[string]any
func GetStringMapString(key string) map[string]string

判断配置是否设置,对与配置的值恰好是该类型的零值,可以用该方法区分这种情况。

viper.IsSet("env")

将配置映射到一个结构体对象。

映射默认会按照成员名称匹配,切不区分大小写。也可以使用标签的 mapstructure 指定配置的 key。

// Config 配置
type Config struct {
	Env   string        `mapstructure:"env"`
	Mysql []MysqlConfig `mapstructure:"mysql"`
}

// MysqlConfig 配置
type MysqlConfig struct {
	Host string `mapstructure:"host"`
	Port int    `mapstructure:"port"`
}

var C Config
err := viper.Unmarshal(&C)