Go 语言中强大的配置管理库—Viper
Viper 是 Go 语言中强大的配置管理库,广泛用于云原生和微服务开发中。它支持多种配置文件格式(如 YAML、JSON、TOML 等)、环境变量、命令行参数以及远程配置管理。
Viper 的主要功能
1. 支持多种格式的配置文件:
• YAML、JSON、TOML、HCL、Java properties 等。
2. 读取环境变量:
• 支持从系统环境变量加载配置。
3. 支持命令行参数:
• 可以与 pflag 或 flag 集成,读取命令行标志。
4. 动态配置更新:
• 可以监听文件变化,实时更新配置。
5. 远程配置支持:
• 支持从 Consul、Etcd 等远程配置服务加载配置。
6. 默认值设置:
• 为配置项设置默认值,在未定义时使用。
7. 嵌套配置支持:
• 支持嵌套结构的配置项。
安装
在项目中安装 Viper:
go get -u github.com/spf13/viper
基本使用示例
1. 读取 YAML 配置文件
假设有一个 config.yaml 文件:
app:
name: "MyApp"
version: "1.0.0"
server:
port: 8080
host: "localhost"
使用 Viper 读取配置:
package main
import (
"fmt"
"github.com/spf13/viper"
)
func main() {
// 设置配置文件名和路径
viper.SetConfigName("config") // 配置文件名(不包含扩展名)
viper.SetConfigType("yaml") // 配置文件类型
viper.AddConfigPath(".") // 配置文件路径
// 读取配置
if err := viper.ReadInConfig(); err != nil {
panic(fmt.Errorf("fatal error reading config file: %w", err))
}
// 获取配置值
appName := viper.GetString("app.name")
appVersion := viper.GetString("app.version")
serverPort := viper.GetInt("server.port")
serverHost := viper.GetString("server.host")
fmt.Printf("App: %s v%s running on %s:%d\n", appName, appVersion, serverHost, serverPort)
}
2. 设置默认值
viper.SetDefault("app.name", "DefaultApp")
viper.SetDefault("server.port", 3000)
appName := viper.GetString("app.name") // DefaultApp
serverPort := viper.GetInt("server.port") // 3000
3. 读取环境变量
可以绑定环境变量,便于动态设置:
package main
import (
"fmt"
"github.com/spf13/viper"
)
func main() {
// 绑定环境变量
viper.AutomaticEnv()
// 设置别名(可选)
_ = viper.BindEnv("server.port", "APP_SERVER_PORT")
// 获取环境变量的值
serverPort := viper.GetInt("server.port")
fmt.Printf("Server Port from ENV: %d\n", serverPort)
}
运行时设置环境变量:
export APP_SERVER_PORT=9090
go run main.go
# Output: Server Port from ENV: 9090
4. 动态监听配置文件变化
支持热加载配置文件的功能:
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config file changed:", e.Name)
})
5. 嵌套结构绑定
支持将配置绑定到结构体:
package main
import (
"fmt"
"github.com/spf13/viper"
)
type Config struct {
App struct {
Name string `mapstructure:"name"`
Version string `mapstructure:"version"`
}
Server struct {
Port int `mapstructure:"port"`
Host string `mapstructure:"host"`
}
}
func main() {
viper.SetConfigFile("config.yaml")
if err := viper.ReadInConfig(); err != nil {
panic(fmt.Errorf("fatal error reading config file: %w", err))
}
var config Config
if err := viper.Unmarshal(&config); err != nil {
panic(fmt.Errorf("unable to decode config into struct: %w", err))
}
fmt.Printf("App: %s v%s running on %s:%d\n",
config.App.Name, config.App.Version, config.Server.Host, config.Server.Port)
}
6. 命令行参数结合 pflag 使用
package main
import (
"fmt"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
func main() {
// 定义命令行标志
pflag.Int("port", 8080, "Server port")
pflag.Parse()
// 将命令行标志绑定到 Viper
_ = viper.BindPFlags(pflag.CommandLine)
// 获取值
serverPort := viper.GetInt("port")
fmt.Printf("Server Port: %d\n", serverPort)
}
运行时设置参数:
go run main.go --port=9090
# Output: Server Port: 9090