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: 8080host: "localhost"
使用 Viper 读取配置:
package mainimport ("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 mainimport ("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 mainimport ("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 Configif 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 mainimport ("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