
Viper
Viper
安装 Viper
1
2
3
4
|
go get -u github.com/spf13/viper
|
Viper 实践
设置默认值, 在项目中设置默认值非常的有必要。
1
2
| viper.SetDefault("ConfDir", "./conf/")
|
读取配置文件
Viper 支持搜索多个路径, 但是目前 Viper 只支持读取一个配置文件。
Viper 没有默认的配置文件搜索路径, 需要程序自行定义。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| func main() {
// 读取配置文件
// SetConfigFile 设置完整配置文件
//viper.SetConfigFile("config.yaml")
// SetConfigName 设置配置文件名称 - 不需要定义文件扩展名
viper.SetConfigName("config")
// SetConfigType 设置配置文件类型 - 专用于 远程配置中心定义类型
//viper.SetConfigType("yaml")
// AddConfigPath 添加配置文件读取目录, 支持添加多个
// 这里注意 搜索路径是从上到下搜索, 如果下面有配置写入会生成
viper.AddConfigPath("./conf/")
viper.AddConfigPath("./")
// ReadInConfig 查找并读取配置文件
if err := viper.ReadInConfig(); err != nil {
panic(fmt.Errorf("Read Config Error %s \n", err))
}
}
|
写入配置文件
- 写入配置文件一般用于程序运行时需要更新配置文件时使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
func main() {
// 写入配置文件
// WriteConfig 将当前配置 写入/覆盖 AddConfigPath 和 SetConfigName 设置的预定路径。
if err := viper.WriteConfig(); err != nil {
fmt.Printf("WriteConfig Failed Error %s \n", err)
return
}
// SafeWriteConfig 将当前配置 写入设置的预定路径, 如果存在不会覆盖 而是报错。
if err := viper.SafeWriteConfig(); err != nil {
fmt.Printf("Safe WriteConfig Failed Error %s \n", err)
return
}
// WriteConfigAs 将当前配置 写入/覆盖 到自定义的路径中
if err := viper.WriteConfigAs("./config"); err != nil {
fmt.Printf("WriteConfig As Failed Error %s \n", err)
return
}
// SafeWriteConfigAs 将当前配置 写入 到自定义的路径中, 如果文件存在不会覆盖 而是报错。
if err := viper.SafeWriteConfigAs("./config"); err != nil {
fmt.Printf("Safe WriteConfig As Failed Error %s \n", err)
return
}
}
|
监控并重新读取配置文件
- Viper 支持在运行时实时读取配置文件, 并且动态加载配置。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
func main(){
// WatchConfig 监控配置文件变化
viper.WatchConfig()
// OnConfigChange 是监控配置文件有变化后调用的一个回调函数
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config file changed:", e.Name)
})
}
|
应用使用例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
func InitViper() {
// 设置默认值
viper.SetDefault("ConfDir", "./conf/")
// 读取配置文件
// SetConfigFile 设置完整配置文件
//viper.SetConfigFile("config.yaml")
// SetConfigName 设置配置文件名称 - 不需要定义文件扩展名
viper.SetConfigName("config")
// SetConfigType 设置配置文件类型 - 专用于 远程配置中心定义类型
//viper.SetConfigType("yaml")
// AddConfigPath 添加配置文件读取目录, 支持添加多个
viper.AddConfigPath("./conf/")
// ReadInConfig 查找并读取配置文件
if err := viper.ReadInConfig(); err != nil {
panic(fmt.Errorf("Read Config Error %s \n", err))
}
// WatchConfig 监控配置文件变化
viper.WatchConfig()
// OnConfigChange 是监控配置文件有变化后调用的一个回调函数
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("配置文件发生变化:", e.Name)
})
// 写入配置文件
// SafeWriteConfig 将当前配置 写入设置的预定路径, 如果存在不会覆盖 而是报错。
if err := viper.SafeWriteConfig(); err != nil {
fmt.Printf("Safe WriteConfig Failed Error %s \n", err)
return
}
}
func main() {
InitViper()
r := gin.Default()
r.GET("/version", func(c *gin.Context) {
c.String(http.StatusOK, viper.GetString("version"))
})
addr := fmt.Sprintf("%s:%s", viper.GetString("host"), viper.GetString("port"))
if err := r.Run(addr); err != nil {
fmt.Printf("Gin Run Failed Error %v \n", err)
return
}
}
|
别名 Alias
1
2
3
4
5
6
7
8
9
10
11
| // 将lodu 与 Verbose 注册别名, 既关联在一起
viper.RegisterAlias("loud", "Verbose")
// 设置其中一个配置项的 值
viper.Set("loud", true)
// 如下 Get 两个配置项的值都会等于 true
viper.GetBool("loud")
viper.GetBool("Verbose")
|
环境变量
注: 环境变量的使用建议全部使用大写, viper 也会强制转换为大写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
func viperEnv() {
viper.SetEnvPrefix("VIP")
if err := viper.BindEnv("NAME"); err != nil {
fmt.Printf("BindEnv Failed Error %v \n", err)
return
}
if err := os.Setenv("VIP_NAME", "小炒肉"); err != nil {
fmt.Printf("Os Set Env Failed Error %v \n", err)
return
}
fmt.Printf("ViperEnv Get VIP_NAME = [%v] \n", viper.Get("NAME"))
}
func main() {
viperEnv()
}
|
1
2
3
| # 输出结果
ViperEnv Get VIP_NAME = [小炒肉]
|
使用 Flags
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| func viperPFlag() {
// pflag 设置
pflag.Int("flagname", 123, "message flag name")
// 生效配置
pflag.Parse()
// 绑定 pflag
if err := viper.BindPFlags(pflag.CommandLine); err != nil {
fmt.Printf("Bind PFlags Failed Error %v \n", err)
return
}
fmt.Printf("flagname = [%v] \n", viper.GetInt("flagname"))
}
func main() {
viperPFlag()
}
|
1
2
3
4
| # 运行命令 go run main.go --flagname 99998 输出结果
flagname = [99998]
|
定义配置源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
func yamlExample() {
viper.SetConfigType("yaml")
// 定义一个 yaml 的配置源,这里注意 yaml 对格式支持很严格,要对齐首行
var yamlConfig = []byte(`
host: "127.0.0.1"
port: 9999
version: "v1.0"
`)
// 通过 io.Reader 读取 buffer 内的配置
config := bytes.NewBuffer(yamlConfig)
if err := viper.ReadConfig(config); err != nil {
fmt.Printf("Read Buffer Config Failed Error %s \n", err)
return
}
// Get 配置信息
fmt.Printf("Version: %s \n", viper.Get("version"))
}
func main() {
yamlExample()
}
|
1
2
3
4
| # 输出结果
Version: v1.0
|
远程 Key/Value 存储
etcd
1
2
3
4
5
6
7
| viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/")
// 设置 etcd 中存储类型。
viper.SetConfigType("json")
err := viper.ReadRemoteConfig()
|
Consul
1
2
3
4
5
6
| viper.AddRemoteProvider("consul", "http://127.0.0.1:8500", "MY_CONSUL_KEY")
viper.SetConfigType("json")
err := viper.ReadRemoteConfig()
|
获取 Viper 值
访问嵌套的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| {
"host": {
"address": "127.0.0.1",
"port": 9999
},
"datastore": {
"mysql": {
"host": "127.0.0.1",
"port": 3306
},
"redis": {
"host": "127.0.0.1",
"port": 6379
}
}
}
|
访问嵌套例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| func jsonExample() {
viper.SetConfigType("json")
var jsonConfig = []byte(`
{
"host": {
"address": "127.0.0.1",
"port": 9999
},
"datastore": {
"mysql": {
"host": "127.0.0.1",
"port": 3306
},
"redis": {
"host": "127.0.0.1",
"port": 6379
}
}
}
`)
// 通过 io.Reader 读取 buffer 内的配置
config := bytes.NewBuffer(jsonConfig)
if err := viper.ReadConfig(config); err != nil {
fmt.Printf("Read Buffer Config Failed Error %s \n", err)
return
}
// 访问嵌套 通过 [ . ] 来直接获取
fmt.Printf("Mysql: [%s:%v] \nRedis:[%s:%v] \n",
viper.Get("datastore.mysql.host"),
viper.Get("datastore.mysql.port"),
viper.Get("datastore.redis.host"),
viper.Get("datastore.redis.port"),
)
}
|
1
2
3
| # 输出结果
Mysql: [127.0.0.1:3306]
Redis:[127.0.0.1:6379]
|
反序列化
1
2
3
4
5
6
7
8
9
|
host: "127.0.0.1"
port: 9999
version: "v1.1"
mysql:
host: "127.0.0.1"
port: 3306
dbname: "viper_demo"
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
| type Config struct {
// 结构体 viper 配置文件 tag 统一使用 mapstructure 这个tag
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
Version string `mapstructure:"version"`
MysqlConfig `mapstructure:"mysql"`
}
type MysqlConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
DBName string `mapstructure:"dbname"`
}
// 定义一个 Config 类型的实例 c
var c Config
func InitViper() {
// 设置默认值
viper.SetDefault("ConfDir", "./conf/")
// SetConfigName 设置配置文件名称 - 不需要定义文件扩展名
viper.SetConfigName("config")
// SetConfigType 设置配置文件类型 - 专用于 远程配置中心定义类型
//viper.SetConfigType("yaml")
// AddConfigPath 添加配置文件读取目录, 支持添加多个
viper.AddConfigPath("./conf/")
// ReadInConfig 查找并读取配置文件
if err := viper.ReadInConfig(); err != nil {
panic(fmt.Errorf("Read Config Error %s \n", err))
}
// WatchConfig 监控配置文件变化
viper.WatchConfig()
// OnConfigChange 是监控配置文件有变化后调用的一个回调函数
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("配置文件发生变化:", e.Name)
})
// 将配置 反序列化到 实例 c 中
if err := viper.Unmarshal(&c); err != nil {
fmt.Printf("Viper Unmarshal Failed Error %v \n", err)
return
}
}
func main() {
InitViper()
fmt.Printf("c = [%#v]\n", c)
}
|
1
2
3
4
5
| # 输出结果
c = [main.Config{Host:"127.0.0.1", Port:9999, Version:"v1.1", \
MysqlConfig:main.MysqlConfig{Host:"127.0.0.1", Port:3306, DBName:"viper_demo"}}]
|