Go常见包 — viper
前置: viper基础操作超级详解【1】
读取配置
从io.Reader
中读取
viper 支持从io.Reader
中读取配置。这种形式很灵活,来源可以是文件,也可以是程序中生成的字符串,甚至可以从网络连接中读取的字节流。
package main
import (
"bytes"
"fmt"
"log"
"github.com/spf13/viper"
)
func main() {
viper.SetConfigType("toml")
tomlConfig := []byte(`
app_name = "awesome web"
# possible values: DEBUG, INFO, WARNING, ERROR, FATAL
log_level = "DEBUG"
[mysql]
ip = "127.0.0.1"
port = 3306
user = "dj"
password = 123456
database = "awesome"
[redis]
ip = "127.0.0.1"
port = 7381
`)
err := viper.ReadConfig(bytes.NewBuffer(tomlConfig))
if err != nil {
log.Fatal("read config failed: %v", err)
}
fmt.Println("redis port: ", viper.GetInt("redis.port"))
}
Unmarshal
viper 支持将配置Unmarshal
l到一个结构体中,为结构体中的对应字段赋值。
package main
import (
"fmt"
"log"
"github.com/spf13/viper"
)
type Config struct {
AppName string
LogLevel string
MySQL MySQLConfig
Redis RedisConfig
}
type MySQLConfig struct {
IP string
Port int
User string
Password string
Database string
}
type RedisConfig struct {
IP string
Port int
}
func main() {
viper.SetConfigName("config")
viper.SetConfigType("toml")
viper.AddConfigPath(".")
err := viper.ReadInConfig()
if err != nil {
log.Fatal("read config failed: %v", err)
}
var c Config
viper.Unmarshal(&c)
fmt.Println(c.MySQL)
}
编译,运行程序,输出:
{127.0.0.1 3306 dj 123456 awesome}
保存配置
有时候,我们想要将程序中生成的配置,或者所做的修改保存下来。viper 提供了接口!
WriteConfig
:将当前的 viper 配置写到预定义路径,如果没有预定义路径,返回错误。将会覆盖当前配置;SafeWriteConfig
:与上面功能一样,但是如果配置文件存在,则不覆盖;WriteConfigAs
:保存配置到指定路径,如果文件存在,则覆盖;SafeWriteConfig
:与上面功能一样,但是入股配置文件存在,则不覆盖。
下面我们通过程序生成一个config.toml
配置:
package main
import (
"log"
"github.com/spf13/viper"
)
func main() {
viper.SetConfigName("config")
viper.SetConfigType("toml")
viper.AddConfigPath(".")
viper.Set("app_name", "awesome web")
viper.Set("log_level", "DEBUG")
viper.Set("mysql.ip", "127.0.0.1")
viper.Set("mysql.port", 3306)
viper.Set("mysql.user", "root")
viper.Set("mysql.password", "123456")
viper.Set("mysql.database", "awesome")
viper.Set("redis.ip", "127.0.0.1")
viper.Set("redis.port", 6381)
err := viper.SafeWriteConfig()
if err != nil {
log.Fatal("write config failed: ", err)
}
}
编译、运行程序,生成的文件如下:
app_name = "awesome web"
log_level = "DEBUG"
[mysql]
database = "awesome"
ip = "127.0.0.1"
password = "123456"
port = 3306
user = "root"
[redis]
ip = "127.0.0.1"
port = 6381
监听文件修改
viper 可以监听文件修改,热加载配置。因此不需要重启服务器,就能让配置生效。
package main
import (
"fmt"
"log"
"time"
"github.com/spf13/viper"
)
func main() {
viper.SetConfigName("config")
viper.SetConfigType("toml")
viper.AddConfigPath(".")
err := viper.ReadInConfig()
if err != nil {
log.Fatal("read config failed: %v", err)
}
viper.WatchConfig()
fmt.Println("redis port before sleep: ", viper.Get("redis.port"))
time.Sleep(time.Second * 10)
fmt.Println("redis port after sleep: ", viper.Get("redis.port"))
}
只需要调用viper.WatchConfig
,viper
会自动监听配置修改。如果有修改,重新加载的配置。
上面程序中,我们先打印redis.port
的值,然后Sleep
10s。在这期间修改配置中redis.port
的值,Sleep
结束后再次打印。 发现打印出修改后的值:
redis port before sleep: 7381
redis port after sleep: 73810
另外,还可以为配置修改增加一个回调:
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Printf("Config file:%s Op:%s\n", e.Name, e.Op)
})
这样文件修改时会执行这个回调。
viper 使用fsnotify
这个库来实现监听文件修改的功能。