命令记不住

登陆

viper 配置文件解析

viper配置文件解析

1.配置文件解析

  • go-ini
  • viper

    • 配置两种方法:

        1. 直接通过viper取
        1. 定义全局变量,读取完配置反序列化到变量中,其他模块通过全局变量获取配置信息

WatchConfig发生变化后需要手动的再把更新后的配置给赋值给全局变量
如果使用嵌套的结构体要使用专用的mapstructure tag

viper1

应用:viper+consul实现配置热更新。

2.基本使用

1.viper示例
func main() {
	viper.SetConfigName("config")  // 指定配置文件名称(不需要带后缀)
	viper.SetConfigType("yaml")    // 指定配置文件类型
	viper.AddConfigPath("./conf/") // 指定查找配置文件的路径(这里使用相对路径)
	err := viper.ReadInConfig()    // 读取配置信息
	if err != nil {                // 读取配置信息失败
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}
	r := gin.Default()
	if err := r.Run(fmt.Sprintf(":%d", viper.Get("port"))); err != nil {
		panic(err)
	}
}
2.设置默认值
viper.SetDefault("ContentDir", "content")
viper.SetDefault("LayoutDir", "layouts")
viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})
3.监控并重新读取配置文件
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
	// 配置文件发生变更之后会调用的回调函数
	fmt.Println("Config file changed:", e.Name)
})
4.读取环境变量
viper.SetEnvPrefix("GIN")
viper.AutomaticEnv()  // 环境变量中GIN开头的
viper.BindEnv("mode") // GIN_MODE
5.从命令行flag参数读取
package main
import (
"flag"
"github.com/spf13/pflag"
)
func main() {
  // 使用标准库 "flag" 包
  flag.Int("flagname", 1234, "help message for flagname")
  pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
  pflag.Parse()
  viper.BindPFlags(pflag.CommandLine)
  i := viper.GetInt("flagname") // 从 viper 检索值
  ...
}
6.从远程配置仓库读取

etcd

viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/hugo.json")
viper.SetConfigType("json") // 因为在字节流中没有文件扩展名,所以这里需要设置下类型。支持的扩展名有 "json", "toml", "yaml", "yml", "properties", "props", "prop", "env","dotenv"
err := viper.ReadRemoteConfig()

consule

viper.AddRemoteProvider("consul", "localhost:8500", "MY_CONSUL_KEY")
viper.SetConfigType("json") // 需要显示设置成json
err := viper.ReadRemoteConfig()
fmt.Println(viper.Get("port"))     // 8080
fmt.Println(viper.Get("hostname")) // liwenzhou.co

3.从Viper获取值

获取值方法

获取值使用以下方法,注意 Get 返回的是空接口类型的值,后续需要根据实际情况做类型转换

Get(key string) : interface{}
GetBool(key string) : bool
GetFloat64(key string) : float64
GetInt(key string) : int
GetIntSlice(key string) : []int
GetString(key string) : string
GetStringMap(key string) : map[string]interface{}
GetStringMapString(key string) : map[string]string
GetStringSlice(key string) : []string
GetTime(key string) : time.Time
GetDuration(key string) : time.Duration
IsSet(key string) : bool
AllSettings() : map[string]interface{}
1.获取嵌套的键
{
  "datastore.metric.host": "0.0.0.0",
  "host": {
  "address": "localhost",
  "port": 5799
  },
  "datastore": {
  "metric": {
  "host": "127.0.0.1",
  "port": 3099
  		  },
  "warehouse": {
  "host": "198.0.0.1",
  "port": 2112
  }
}
}

获取嵌套的值

GetString("datastore.metric.host") // (返回 "127.0.0.1")
2.获取配置子树
app:
cache1:
max-items: 100
item-size: 64
cache2:
max-items: 200
item-size: 80

获取上面配置文件中 cache2 子树的配置:

viper.Sub("app.cache1")
3.反序列化
type config struct {
	Port    int
	Name    string
	PathMap string `mapstructure:"path_map"`
}
var C config
err := viper.Unmarshal(&C)
if err != nil {
	t.Fatalf("unable to decode into struct, %v", err)
}

将viper中的配置写入配置文件

viper.WriteConfig() // 将当前配置写入“viper.AddConfigPath()”和“viper.SetConfigName”设置的预定义路径
viper.SafeWriteConfig()
viper.WriteConfigAs("/path/to/my/.config")
viper.SafeWriteConfigAs("/path/to/my/.config") // 因为该配置文件写入过,所以会报错
viper.SafeWriteConfigAs("/path/to/my/.other_config")
推荐阅读