在 Go 中使用 Viper 加载配置文件
viper是国外大神spf13写的开源配置解决方案。 viper 的 Github 是:https://github.com/spf13/viper
。
优秀go项目使用viper
- Hugo
- EMC RexRay
- Imgur’s Incus
- Nanobox/Nanopack
- Docker Notary
- BloomApi
- doctl
- Clairctl
viper优势
- 设置默认值
- 可以读取如下格式的配置⽂件:JSON、TOML、YAML、HCL
- 监控配置文件改动,并热加载配置文件
- 从环境变量读取配置
- 从远程配置中心读取配置(etcd/consul),并监控变动
- 从命令行flag中读取配置
- 从缓存中读取配置
- 支持直接设置配置项的值
Viper 配置读取顺序
- viper.Set() 所设置的值
- 命令行 flag
- 环境变量
- 配置文件
- 配置中心:etcd/consul
- 默认值
Viper 非常强大,而且 Viper 用起来也很方便。
使用步骤
- 初始化配置文件(设置配置文件的目录、文件名、后缀、环境变量等)
- 调用viper.GetString()、viper.GetInt() 和viper.GetBool() 获取配置值
仅仅使用两步,就可以应对大多数的业务场景。
使用例子:
package config
import (
"log"
"strings"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
)
type Config struct {
name string
}
func Init(cfg string) error {
c := Config {
name:cfg,
}
if err := c.configInit(); err != nil {
return err
}
c.watchConfig()
return nil
}
func (c *Config)configInit() error {
if c.name != "" {
viper.SetConfigFile(c.name)
} else {
viper.AddConfigPath("F:\\go_home\\src\\serverapi\\conf") // tm 被windows的坑了。一定要绝对路径?
viper.SetConfigName("config")
}
viper.SetConfigType("yaml")
viper.AutomaticEnv()
viper.SetEnvPrefix("SERVERAPI")
replacer := strings.NewReplacer(".", "_")
viper.SetEnvKeyReplacer(replacer)
if err := viper.ReadInConfig(); err != nil {
return err
}
return nil
}
func (c *Config)watchConfig() {
viper.WatchConfig()
viper.OnConfigChange(func(in fsnotify.Event) {
log.Printf("config file change :%s", in.Name)
})
}
测试程序:
package config
import (
"fmt"
"testing"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
var (
cfg = pflag.StringP("config", "c", "", "config for serverapi")
)
func TestConfig(test *testing.T) {
// 配置文件
pflag.Parse()
if err := Init(*cfg); err != nil {
panic(err)
}
fmt.Println("config: "+viper.GetString("runmode"))
}
结果:
=== RUN TestConfig
config: debug
--- PASS: TestConfig (0.02s)
PASS
Viper 高级用法
-
获取子级配置
mysql: ip: localhost port: 3306
GetString(“mysql.port”)
-
通过环境变量来设置配置值
比如:export SERVERAPI_ADDR=:7777
-
热更新
viper.WatchConfig() //设置对配置文件监控更新 viper.OnConfigChange(func(in fsnotify.Event) { log.Printf(“config file change :%s”, in.Name) })
- 解析配置(将配置绑定到某个结构体、map)
- Unmarshal(rawVal interface{}) : error
- UnmarshalKey(key string, rawVal interface{}) : error
var mysql MySQL err := UnmarshalKey(“mysql”, &mysql) // 将配置解析到 mysql 变量 if err != nil { panic(err) }
总结
从上面的介绍和demo来看,viper确实使用简单,但功能强大。可以在平时项目开发中用起来。