配置读取
Viper 支持从多种来源读取配置,包括配置文件、环境变量、命令行参数等。
配置文件读取
基础配置读取
go
package main
import (
"fmt"
"github.com/spf13/viper"
)
func main() {
v := viper.New()
v.SetConfigName("config") // 配置文件名 (无扩展名)
v.SetConfigType("yaml") // 配置文件类型
v.AddConfigPath(".") // 配置文件路径
v.AddConfigPath("./config") // 多个路径
if err := v.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
fmt.Println("配置文件未找到")
} else {
fmt.Printf("读取配置文件错误: %v\n", err)
}
}
fmt.Println(v.GetString("app.name"))
}支持的配置格式
| 格式 | 扩展名 | SetConfigType |
|---|---|---|
| YAML | .yaml, .yml | yaml |
| JSON | .json | json |
| TOML | .toml | toml |
| HCL | .hcl | hcl |
| INI | .ini | ini |
| Properties | .properties | properties |
YAML 配置文件
yaml
app:
name: myapp
version: 1.0.0
port: 8080
database:
host: localhost
port: 3306
name: mydb
user: root
password: password
cache:
enabled: true
ttl: 3600JSON 配置文件
json
{
"app": {
"name": "myapp",
"version": "1.0.0",
"port": 8080
},
"database": {
"host": "localhost",
"port": 3306,
"name": "mydb",
"user": "root",
"password": "password"
}
}TOML 配置文件
toml
[app]
name = "myapp"
version = "1.0.0"
port = 8080
[database]
host = "localhost"
port = 3306
name = "mydb"
user = "root"
password = "password"获取配置值
基本类型
go
// 字符串
name := viper.GetString("app.name")
// 整数
port := viper.GetInt("app.port")
// 布尔值
enabled := viper.GetBool("cache.enabled")
// 浮点数
ratio := viper.GetFloat64("cache.ratio")
// 时间
timeout := viper.GetDuration("http.timeout")
// 时间戳
time := viper.GetTime("app.created_at")
// 字节数组
data := viper.GetBytes("app.secret")复杂类型
go
// 字符串数组
hosts := viper.GetStringSlice("database.hosts")
// 整数数组
ports := viper.GetIntSlice("database.ports")
// 字符串映射
tags := viper.GetStringMap("app.tags")
// 字符串映射字符串
envs := viper.GetStringMapString("app.envs")
// 任意类型
value := viper.Get("app.config")获取嵌套配置
go
// 使用点号访问嵌套配置
dbHost := viper.GetString("database.host")
dbPort := viper.GetInt("database.port")
// 多层嵌套
maxConn := viper.GetInt("database.connection.max")环境变量读取
自动读取环境变量
go
viper.AutomaticEnv()
// 环境变量 APP_NAME 对应 app.name
name := viper.GetString("app.name")设置环境变量前缀
go
viper.SetEnvPrefix("APP")
// 环境变量 APP_PORT 对应 port
port := viper.GetInt("port")自定义环境变量绑定
go
viper.BindEnv("database.host", "DB_HOST")
viper.BindEnv("database.port", "DB_PORT")
host := viper.GetString("database.host")环境变量替换
go
// 使用环境变量替换配置值
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
// app.name -> APP_NAME
name := viper.GetString("app.name")环境变量示例
bash
export APP_NAME=myapp
export APP_PORT=8080
export DB_HOST=localhost
export DB_PORT=3306命令行参数读取
使用 pflag
go
import (
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
func main() {
pflag.String("config", "config.yaml", "config file path")
pflag.String("port", "8080", "server port")
pflag.Parse()
viper.BindPFlags(pflag.CommandLine)
config := viper.GetString("config")
port := viper.GetInt("port")
}使用 flag
go
import (
"flag"
"github.com/spf13/viper"
)
func main() {
flag.String("config", "config.yaml", "config file path")
flag.Int("port", 8080, "server port")
flag.Parse()
viper.BindFlagValues(flag.CommandLine)
config := viper.GetString("config")
port := viper.GetInt("port")
}默认值设置
设置单个默认值
go
viper.SetDefault("app.name", "myapp")
viper.SetDefault("app.port", 8080)
viper.SetDefault("database.host", "localhost")
viper.SetDefault("database.port", 3306)设置嵌套默认值
go
viper.SetDefault("database.connection.max", 100)
viper.SetDefault("database.connection.timeout", "30s")使用配置结构体
go
type Config struct {
App struct {
Name string `mapstructure:"name"`
Port int `mapstructure:"port"`
} `mapstructure:"app"`
Database struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
} `mapstructure:"database"`
}
func main() {
viper.SetConfigFile("config.yaml")
viper.ReadInConfig()
var config Config
viper.Unmarshal(&config)
fmt.Println(config.App.Name)
fmt.Println(config.Database.Host)
}远程配置读取
Consul 配置中心
go
import (
"github.com/spf13/viper"
"github.com/spf13/viper/remote"
)
func main() {
viper.AddRemoteProvider("consul", "localhost:8500", "/config/myapp")
viper.SetConfigType("yaml")
if err := viper.ReadRemoteConfig(); err != nil {
log.Fatal(err)
}
name := viper.GetString("app.name")
}Etcd 配置中心
go
viper.AddRemoteProvider("etcd", "http://localhost:2379", "/config/myapp")
viper.SetConfigType("yaml")
viper.ReadRemoteConfig()Firestore 配置中心
go
viper.AddRemoteProvider("firestore", "https://firestore.googleapis.com", "config/myapp")
viper.SetConfigType("json")
viper.ReadRemoteConfig()多配置源优先级
优先级顺序
1. 命令行参数 (最高)
2. 环境变量
3. 配置文件
4. 默认值 (最低)配置覆盖示例
go
func main() {
// 1. 设置默认值
viper.SetDefault("app.port", 8080)
// 2. 读取配置文件
viper.SetConfigFile("config.yaml")
viper.ReadInConfig()
// 3. 读取环境变量
viper.AutomaticEnv()
// 4. 读取命令行参数
pflag.Int("port", 8080, "server port")
pflag.Parse()
viper.BindPFlags(pflag.CommandLine)
// 最终值取决于最高优先级
port := viper.GetInt("app.port")
fmt.Println(port)
}检查配置是否存在
IsSet 检查
go
if viper.IsSet("app.name") {
name := viper.GetString("app.name")
}
if viper.IsSet("database") {
// database 配置存在
}InConfig 检查
go
// 检查是否在配置文件中
if viper.InConfig("app.name") {
// app.name 在配置文件中定义
}
// 检查是否在环境变量中
if viper.InConfig("APP_NAME") {
// APP_NAME 环境变量存在
}配置搜索路径
添加多个搜索路径
go
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath("/etc/myapp")
viper.AddConfigPath("$HOME/.myapp")
viper.AddConfigPath(".")
viper.ReadInConfig()使用绝对路径
go
viper.SetConfigFile("/etc/myapp/config.yaml")
if err := viper.ReadInConfig(); err != nil {
log.Fatal(err)
}配置文件监控
监听配置文件变更
go
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Printf("配置文件变更: %s\n", e.Name)
// 处理配置变更逻辑
})
viper.WatchConfig()完整示例
go
func main() {
viper.SetConfigFile("config.yaml")
viper.ReadInConfig()
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
log.Printf("配置文件变更: %s, 操作: %v", e.Name, e.Op)
// 重新加载配置
if err := viper.ReadInConfig(); err != nil {
log.Printf("重新加载配置失败: %v", err)
}
// 更新应用配置
updateConfig()
})
// 启动应用
startApp()
}子配置对象
创建子 viper
go
sub := viper.Sub("database")
if sub != nil {
host := sub.GetString("host")
port := sub.GetInt("port")
}使用子配置
go
// 获取 database 子配置
subViper := viper.Sub("database")
// 使用子配置读取值
host := subViper.GetString("host")
// 子配置解析为结构体
type DatabaseConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
}
var dbConfig DatabaseConfig
subViper.Unmarshal(&dbConfig)最佳实践
- 设置默认值:为关键配置设置合理的默认值
- 多源组合:配置文件 + 环境变量 + 命令行参数
- 优先级理解:了解配置源的优先级顺序
- 类型安全:使用结构体 Unmarshal 获取配置
- 错误处理:处理配置文件未找到和解析错误
- 配置路径:提供多个配置搜索路径
- 环境变量:使用 AutomaticEnv 自动读取