文档:https://pkg.go.dev/github.com/spf13/viper
viper 支持Yaml、Json、TOML、HCL 等格式,读取非常的方便

type DecoderConfigOption

json解析映射配置

  1. type DecoderConfigOption func(*mapstructure.DecoderConfig)

func DecodeHook(hook mapstructure.DecodeHookFunc) DecoderConfigOption

  1. # 默认的规则如下
  2. mapstructure.ComposeDecodeHookFunc(
  3. mapstructure.StringToTimeDurationHookFunc(),
  4. mapstructure.StringToSliceHookFunc(","),
  5. )

type StringReplacer

  1. type StringReplacer interface {
  2. // Replace returns a copy of s with all replacements performed.
  3. Replace(s string) string
  4. }

type Option

func EnvKeyReplacer(r StringReplacer) Option 设置一个替换程序,用于将环境变量映射到内部键
func KeyDelimiter(d string) Option 设置分隔符,默认是”.”

type Viper

func GetViper() Viper 获取全局Viper实例
func New()
Viper New返回一个初始化的Viper实例
func NewWithOptions(opts …Option) Viper
func Sub(key string)
Viper Sub返回新的Viper实例,表示该实例的一个子树。Sub对键不区分大小写。

本地读取

func (v Viper) AddConfigPath(in string) 配置文件的父级路径
func (v
Viper) SetConfigFile(in string) 显式地定义配置文件的路径、名称和扩展名
func (v Viper) SetConfigName(in string) 设置配置文件的名称。不包括扩展
func (v
Viper) ReadInConfig() error 加载配置文件
func (v Viper) SetConfigPermissions(perm os.FileMode) 设置配置文件的权限
func (v
Viper) SetConfigType(in string) 设置后缀名
func (v *Viper) SetTypeByDefaultValue(enable bool) 以设定的默认值的type作为真实type,而不是配置文件中的

  1. #app.toml
  2. [mysql]
  3. host = "1.1.1.1"
  4. port = "3306"
  5. database = "xxxx"
  6. user = "xxxx"
  7. password = "1234"
  8. charset = "utf8"
  9. sql_log = true
  10. MaxIdleConns = 5 # 空闲时最大的连接数
  11. MaxOpenConns = 20 # 最大的连接数
  12. [redis]
  13. Address = "1.1.1.1:6379" # ip地址+端口号
  14. MaxIdle = 16 # 最大空闲数
  15. MaxActive = 20 # 连接池的最大数据库连接数,设为0表示无限制
  16. IdleTimeout = 3000 # 客户端超时时间单位是毫秒
  1. func main() {
  2. v := viper.New()
  3. v.SetConfigName("app")
  4. v.AddConfigPath("./")
  5. //v.AddConfigPath("%GOPATH/src/")
  6. v.SetConfigType("toml")
  7. //v.SetConfigFile("/home/uhome/app/configs/app.toml") //这样写简单明了
  8. if err := v.ReadInConfig();err != nil {
  9. fmt.Printf("err:%s\n",err)
  10. }
  11. fmt.Println(v.AllKeys())
  12. fmt.Println(v.AllSettings())
  13. fmt.Println(v.Get("mysql.host")) // 键的默认分隔符就是"."
  14. }

获取远程配置

func (v Viper) AddRemoteProvider(provider, endpoint, path string) error 添加远程配置源
func (v
Viper) AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error 同上
func (v *Viper) ReadRemoteConfig() error 加载远程配置文件

  1. viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json")
  2. viper.SetConfigType("json")supported extensions are "json", "toml", "yaml", "yml", "properties"
  3. err := viper.ReadRemoteConfig()

io流配置

func (v *Viper) ReadConfig(in io.Reader) error 加载io流的配置文件

  1. viper.SetConfigType("yaml") // or viper.SetConfigType("YAML")
  2. // any approach to require this configuration into your program.
  3. var yamlExample = []byte(`
  4. Hacker: true
  5. name: steve
  6. hobbies:
  7. - skateboarding
  8. - snowboarding
  9. - go
  10. clothing:
  11. jacket: leather
  12. trousers: denim
  13. age: 35
  14. eyes : brown
  15. beard: true
  16. `)
  17. viper.ReadConfig(bytes.NewBuffer(yamlExample))
  18. viper.Get("name") // this would be "steve"

自定义kv

func (v Viper) Set(key string, value interface{}) 覆盖寄存器中键的值。Set对键不区分大小写
func (v
Viper) SetDefault(key string, value interface{}) 设置默认值

取值或判断值

func (v Viper) AllKeys() []string 所有有值的key
func (v
Viper) AllSettings() map[string]interface{} 合并所有设置并以map[string]接口{}的形式返回
func (v Viper) Get(key string) interface{}
func (v
Viper) GetBool(key string) bool
func (v Viper) GetDuration(key string) time.Duration
func (v
Viper) GetFloat64(key string) float64
func (v Viper) GetInt(key string) int
func (v
Viper) GetInt32(key string) int32
func (v Viper) GetInt64(key string) int64
func (v
Viper) GetIntSlice(key string) []int
func (v Viper) GetSizeInBytes(key string) uint
func (v
Viper) GetString(key string) string
func (v Viper) GetStringMap(key string) map[string]interface{}
func (v
Viper) GetStringMapString(key string) map[string]string
func (v Viper) GetStringMapStringSlice(key string) map[string][]string
func (v
Viper) GetStringSlice(key string) []string
func (v Viper) GetTime(key string) time.Time
func (v
Viper) GetUint(key string) uint
func (v Viper) GetUint32(key string) uint32
func (v
Viper) GetUint64(key string) uint64
func (v Viper) InConfig(key string) bool 检查给定的键(或别名)是否在配置文件中
func (v
Viper) IsSet(key string) bool 检查给定的键(或别名)是否在配置文件中设定了值

配置项合并

func (v Viper) MergeConfig(in io.Reader) error 将in与现有的配置文件合并
func (v
Viper) MergeConfigMap(cfg map[string]interface{}) error 用现有配置从给定的映射中合并配置
func (v *Viper) MergeInConfig() error 合并

嵌套结构体

func (v Viper) Sub(key string) Viper

  1. app:
  2. cache1:
  3. max-items: 100
  4. item-size: 64
  5. cache2:
  6. max-items: 200
  7. item-size: 80
  8. subv := viper.Sub("app.cache1")
  9. subv.GetInt64("max-items") // 100
  10. subv.GetInt64("item-size") // 64

监听配置变化

func (v Viper) WatchConfig() 监视本地配置
func (v
Viper) OnConfigChange(run func(in fsnotify.Event)) 文件发生变化时

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/fsnotify/fsnotify"
  5. "github.com/spf13/viper"
  6. "log"
  7. "time"
  8. )
  9. func main() {
  10. v := viper.New()
  11. v.SetConfigFile("app.toml") //这样写简单明了
  12. if err := v.ReadInConfig(); err != nil {
  13. fmt.Printf("err:%s\n", err)
  14. }
  15. fmt.Println(v.Get("mysql.host")) // 键的默认分隔符就是"."
  16. go func() {
  17. for {
  18. time.Sleep(time.Second * 5)
  19. v.WatchConfig()
  20. v.OnConfigChange(func(e fsnotify.Event) {
  21. log.Println("config file changed", e.Name)
  22. // 这里更新配置。。。
  23. })
  24. }
  25. }()
  26. time.Sleep(20 * time.Second)
  27. }

func (v *Viper) WatchRemoteConfig() error 监视远程配置

  1. var runtime_viper = viper.New()
  2. //增加远程配置
  3. runtime_viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/hugo.yml")
  4. runtime_viper.SetConfigType("yaml")
  5. // 读取远程配置
  6. err := runtime_viper.ReadRemoteConfig()
  7. // 解析到runtime_conf
  8. runtime_viper.Unmarshal(&runtime_conf)
  9. go func(){
  10. for {
  11. time.Sleep(time.Second * 5) // delay after each request
  12. // currently, only tested with etcd support
  13. err := runtime_viper.WatchRemoteConfig()
  14. if err != nil {
  15. log.Errorf("unable to read remote config: %v", err)
  16. continue
  17. }
  18. //5秒将runtime_conf更新一次
  19. runtime_viper.Unmarshal(&runtime_conf)
  20. }
  21. }()

func (v *Viper) WatchRemoteConfigOnChannel() error

配置文件保存

func (v Viper) SafeWriteConfig() error 写入当前文件,如果不存在返回错误,如果存在不会覆盖
func (v
Viper) SafeWriteConfigAs(filename string) error 写入指定文件,如果存在不会覆盖
func (v Viper) WriteConfig() error 将当前的配置写入当前文件,如果不存在返回错误(如果存在,覆盖)
func (v
Viper) WriteConfigAs(filename string) error 将当前的配置写入指定文件(覆盖)

Unmarshal例子

func (v *Viper) Unmarshal(rawVal interface{}, opts …DecoderConfigOption) error 将配置映射到结构体

  1. [mysql]
  2. host = "1.1.1.2"
  3. port = "3306"
  4. dataBase = "xxxx"
  5. user = "xxxx"
  6. passWord = "1234"
  7. charset = "utf8"
  8. sqlLog = true
  9. maxIdleConns = 5 # 空闲时最大的连接数
  10. maxOpenConns = 20 # 最大的连接数
  11. [redis]
  12. host = "1.1.1.1"
  13. port = "6379"
  14. dataBase = "xxxx"
  15. user = "xxxx"
  16. passWord = "1234"
  17. maxIdle = 16 # 最大空闲数
  18. maxActive = 20 # 连接池的最大数据库连接数,设为0表示无限制
  19. idleTimeout = 3000 # 客户端超时时间单位是毫秒
  1. package main
  2. import (
  3. "fmt"
  4. "github.com/spf13/viper"
  5. )
  6. type MysqlConfig struct {
  7. Host string
  8. Port string
  9. DataBase string
  10. }
  11. type RedisConfig struct {
  12. Host string
  13. Port string
  14. DataBase string
  15. }
  16. type config struct {
  17. Mysql MysqlConfig // 变量名与toml中保持一致,首字母大写
  18. Redis RedisConfig
  19. }
  20. func main() {
  21. v := viper.New()
  22. v.SetConfigFile("app.toml") //这样写简单明了
  23. if err := v.ReadInConfig(); err != nil {
  24. fmt.Printf("err:%s\n", err)
  25. }
  26. fmt.Println(v.Get("mysql.host")) // 键的默认分隔符就是"."
  27. var m config
  28. fmt.Println(v.Unmarshal(&m))
  29. fmt.Printf("%+v", m)
  30. }
  31. {Mysql:{Host:1.1.1.2 Port:3306 DataBase:xxxx} Redis:{Host:1.1.1.1 Port:6379 DataBase:xxxx}}
  1. package main
  2. import (
  3. "fmt"
  4. "github.com/spf13/viper"
  5. )
  6. type MysqlConfig struct {
  7. Host string
  8. Port string
  9. DataBase string
  10. }
  11. func main() {
  12. v := viper.New()
  13. v.SetConfigFile("app.toml") //这样写简单明了
  14. if err := v.ReadInConfig(); err != nil {
  15. fmt.Printf("err:%s\n", err)
  16. }
  17. fmt.Println(v.Get("mysql.host")) // 键的默认分隔符就是"."
  18. var m MysqlConfig
  19. fmt.Println(v.Sub("mysql").Unmarshal(&m))
  20. fmt.Printf("%+v", m)
  21. }
  22. {Host:1.1.1.2 Port:3306 DataBase:xxxx}

字段TAG

Viper 使用的是github.com/mitchellh/mapstructure

  1. plugin:
  2. client_cert: false
  3. key: "123"
  4. content_format: "json111"
  5. http_compression: true
  6. http_method: "get"
  7. batch_size: 1000
  8. queue_size: 1500
  9. server_port: 9001
  1. type Config struct {
  2. Client_Cert bool `mapstructure:"client_cert"`
  3. Key string `mapstructure:"key"`
  4. Content_Format string `mapstructure:"content_format"`
  5. Http_Compression bool `mapstructure:"http_compression"`
  6. Http_Method string `mapstructure:"http_method"`
  7. Batch_Size int64 `mapstructure:"batch_size"`
  8. Queue_Size int64 `mapstructure:"queue_size"`
  9. Server_Port int64 `mapstructure:"server_port"`
  10. }
  11. func GetConfig() {
  12. var c Config
  13. path := "app.yml"
  14. v := viper.New()
  15. v.SetConfigFile(path)
  16. if err := v.ReadInConfig(); err != nil {
  17. fmt.Printf("err:%s\n", err)
  18. }
  19. v.Sub("plugin").Unmarshal(&c)
  20. fmt.Printf("%#v\n", c)
  21. }
  22. main.Config{Client_Cert:false, Key:"123", Content_Format:"json111", Http_Compression:true, Http_Method:"get", Batch_Size:1000, Queue_Size:1500, Server_Port:9001}

绑定环境变量

func (v Viper) SetEnvPrefix(in string)
func (v
Viper) BindEnv(input …string) error
func (v Viper) SetEnvKeyReplacer(r strings.Replacer) 设定key的替换
func (v *Viper) SetEnvPrefix(in string) 设定key的前缀,那么就只会加载这个
注意:对大小写敏感
如果需要小写字符串,可使用EnvKeyReplacer

  1. SetEnvPrefix("spf") // 将转换为大写
  2. BindEnv("id")
  3. os.Setenv("SPF_ID", "13")
  4. id := Get("id") // 13

同Flags与cobra一起使用

func (v Viper) BindFlagValue(key string, flag FlagValue) error
func (v
Viper) BindFlagValues(flags FlagValueSet) (err error)
func (v Viper) BindPFlag(key string, flag pflag.Flag) error
func (v Viper) BindPFlags(flags pflag.FlagSet) error

  1. func main() {
  2. // using standard library "flag" package
  3. flag.Int("flag", 1234, "help message for flagname")
  4. pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
  5. fmt.Println(pflag.CommandLine.Args())
  6. pflag.Parse()
  7. viper.BindPFlags(pflag.CommandLine)
  8. i := viper.GetInt("flag") // retrieve value from viper
  9. fmt.Println(i)
  10. }
  1. serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
  2. viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))