go_viper解析
什么是Viper?
Viper是Go应用程序的完整配置解决方案,包括12-Factor应用程序。它旨在在应用程序中工作,并可以处理所有类型的配置需求和格式。它支持:
- 设置默认值
- 从JSON,TOML,YAML,HCL和Java属性配置文件中读取
- 实时观看和重新读取配置文件(可选)
- 从环境变量中读取
- 从远程配置系统(etcd或Consul)读取,并观察变化
- 从命令行标志读取
- 从缓冲区读取
- 设置显式值
Viper可以被认为是所有应用程序配置需求的注册表。
为何选择Viper?
构建现代应用程序时,您不必担心配置文件格式; 你想专注于构建真棒软件。Viper就是为此提供帮助的。
- 以JSON,TOML,YAML,HCL或Java属性格式查找,加载和解组配置文件。
- 提供一种机制来为不同的配置选项设置默认值。
- 提供一种机制来为通过命令行标志指定的选项设置覆盖值。
- 提供别名系统,轻松重命名参数,而不会破坏现有代码。
- 可以很容易地区分用户提供命令行或配置文件与默认值相同的时间。
Viper的赋值
使用默认值
一个好的配置系统将支持默认值。密钥不需要默认值,但如果未通过配置文件,环境变量,远程配置或标志设置密钥,则它非常有用。
viper.SetDefault("ContentDir", "content")
viper.SetDefault("LayoutDir", "layouts")
viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})
Viper读取配置文件
以下是如何使用Viper搜索和读取配置文件的示例。不需要任何特定路径,但应在预期配置文件的位置提供至少一个路径。
viper.SetConfigName("config") // 配置文件的名称(没有扩展名)
viper.AddConfigPath("/etc/appname/") // 查找配置文件的路径。
viper.AddConfigPath("$HOME/.appname") // 多次调用以添加许多搜索路径
viper.AddConfigPath(".") // 可选择在工作目录
err := viper.ReadInConfig() // 查找并读取配置文件,
if err != nil { // 处理读取配置文件的错误panic(fmt.Errorf("Fatal error config file: %s \n", err))
}
viper驱动的应用程序可以在运行时读取配置文件的更新,而不会错过任何一个节拍。
只需告诉viper实例watchConfig即可。您可以选择为Viper提供每次发生更改时运行的功能。
确保在调用之前添加所有configPath WatchConfig()
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {fmt.Println("Config file changed:", e.Name)
})
Viper预定义了许多配置源,例如文件,环境变量,标志和远程K/V存储,但您不受它们的约束。您还可以实现自己的必需配置源并将其提供给viper。
viper.SetConfigType("yaml") // or viper.SetConfigType("YAML")// 你的程序需要的任何配置,如下
var yamlExample = []byte(`
Hacker: true
name: steve
hobbies:
- skateboarding
- snowboarding
- go
clothing:jacket: leathertrousers: denim
age: 35
eyes : brown
beard: true
`)viper.ReadConfig(bytes.NewBuffer(yamlExample))viper.Get("name") // this would be "steve"
viper.Set("Verbose", true)
viper.Set("LogFile", LogFile)
viper.RegisterAlias("loud", "Verbose")
viper.Set("verbose", true) // 与下一行代码效果一样
viper.Set("loud", true) // 与上一行代码效果一样
viper.GetBool("loud") // true
viper.GetBool("verbose") // true
Viper使用环境变量
Viper完全支持环境变量。这使得12个因子应用程序可以开箱即用。有五种方法可以帮助使用ENV:
AutomaticEnv()
BindEnv(string...) : error
SetEnvPrefix(string)
SetEnvKeyReplacer(string...) *strings.Replacer
AllowEmptyEnvVar(bool)
使用ENV变量时,重要的是要认识到Viper将ENV变量视为区分大小写。
Viper提供了一种机制来确保ENV变量是唯一的。通过使用SetEnvPrefix
,您可以告诉Viper在读取环境变量时使用前缀。双方BindEnv
并AutomaticEnv
会使用这个前缀。
使用ENV变量时要认识到的一件重要事情是每次访问时都会读取该值。Viper在BindEnv
调用时不会修复该值。
默认情况下,空环境变量被视为未设置,并将回退到下一个配置源。要将空环境变量视为set,请使用该AllowEmptyEnv
方法。
SetEnvPrefix("spf") //将自动大写
BindEnv("id")
os.Setenv("SPF_ID", "13") // 通常在应用以外完成
id := Get("id") // 13
使用flag
就像BindEnv
,在调用绑定方法时,不会设置该值。这意味着您可以尽早绑定,甚至可以在init()
函数中绑定 。
serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
您还可以绑定一组现有的pflags(pflag.FlagSet)
package mainimport ("fmt""github.com/spf13/pflag""github.com/spf13/viper"
)func main() {// 使用标准库“flag”包pflag.Int("flagname", 1234, "help message for flagname")pflag.Parse()viper.BindPFlags(pflag.CommandLine)i := viper.GetInt("flagname")fmt.Println(i)
}
package mainimport ("flag""fmt""github.com/spf13/pflag""github.com/spf13/viper"
)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") // retrieve value from viperfmt.Println(i)
}
如果您不使用,Viper提供两个Go接口来绑定其他标志系统Pflags
FlagValue
代表一个标志。这是一个关于如何实现此接口的非常简单的示例:
type myFlag struct {}func (f myFlag)HasChanged()bool { return false }func (f myFlag)Name()string { return “ my-flag-name ” }func (f myFlag)ValueString()string { return “ my -flag-value “ }func (f myFlag)ValueType()string { return “ string ” }
一旦你的flag实现了这个接口,你可以告诉Viper绑定它:
viper.BindFlagValue("my-flag-name", myFlag{})
远程key/value存储
要在Viper中启用远程支持,请对viper/remote
包进行空白导入:
import _ "github.com/spf13/viper/remote"
Viper将读取key/value存储(如etcd或Consul)中的路径检索的配置字符串(如JSON,TOML,YAML或HCL)。这些值优先于默认值,但会被从磁盘,标志或环境变量检索的配置值覆盖。
Viper使用crypt从K/V存储中检索配置,这意味着您可以存储加密的配置值,并在拥有正确的gpg密钥环时自动解密。加密是可选的。
crypt
有一个命令行帮助程序,您可以使用它来将配置放入K/V存储区。crypt
在http://127.0.0.1:4001上默认为etcd 。
$ go get github.com/xordataexchange/crypt/bin/crypt
$ crypt set -plaintext /config/hugo.json /Users/hugo/settings/config.json
$ crypt get -plaintext /config/hugo.json
viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json")
viper.SetConfigType("json") //因为字节流中没有文件扩展名,支持的扩展名是“json”,“toml”,“yaml”,“yml”,“properties”,“props”,“prop”
err := viper.ReadRemoteConfig()
viper.AddSecureRemoteProvider("etcd","http://127.0.0.1:4001","/config/hugo.json","/etc/secrets/mykeyring.gpg")
viper.SetConfigType("json") //因为字节流中没有文件扩展名,支持的扩展名是“json”,“toml”,“yaml”,“yml”,“properties”,“props”,“prop”
err := viper.ReadRemoteConfig()
//或者,您可以创建一个新的viper实例
var runtime_viper = viper.New()
runtime_viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/hugo.yml")
runtime_viper.SetConfigType("yaml")
// 第一次从远程配置中读取
err := runtime_viper.ReadRemoteConfig()
//解密配置
runtime_viper.Unmarshal(&runtime_conf)
// 打开一个goroutine来永远监听远程变化
go func(){for {time.Sleep(time.Second * 5) // 每次请求后延迟err := runtime_viper.WatchRemoteConfig()if err != nil {log.Errorf("unable to read remote config: %v", err)continue}//将新配置解组到我们的运行时配置结构中。您还可以使用通道//实现信号以通知系统更改 runtime_viper.Unmarshal(&runtime_conf)}
}()
Viper获取值
在Viper中,有几种方法可以根据值的类型获取值。存在以下功能和方法:
Get(key string) : interface{}
GetBool(key string) : bool
GetFloat64(key string) : float64
GetInt(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{}
如果找不到,每个Get函数都将返回零值。IsSet()
方法检查给定密钥是否存在。
viper.GetString("logfile") // case-insensitive Setting & Getting
if viper.GetBool("verbose") {fmt.Println("verbose enabled")
}
访问嵌套
访问器方法也接受深层嵌套键的格式化路径。例如,如果加载了以下JSON文件:
{"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") // (returns "127.0.0.1")
这符合上面建立的优先规则; 搜索路径将在剩余的配置注册表中级联,直到找到。
但是,如果使用立即值datastore.metric
覆盖(通过标志,环境变量,Set()
方法,…),则所有子键 datastore.metric
变为未定义,它们将被更高优先级的配置级别“遮蔽”。
{"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") // returns "0.0.0.0"
app:cache1:max-items: 100item-size: 64cache2:max-items: 200item-size: 80
subv := viper.Sub("app.cache1")
max-items: 100
item-size: 64
func NewCache(cfg *Viper) *Cache {...}
它根据格式化为的配置信息创建缓存subv
。现在可以轻松地分别创建这两个缓存:
cfg1 := viper.Sub("app.cache1")
cache1 := NewCache(cfg1)cfg2 := viper.Sub("app.cache2")
cache2 := NewCache(cfg2)
您还可以选择Unmarshaling all或特定值到struct,map等。
type config struct {Port intName stringPathMap string `mapstructure:"path_map"`
}var C configerr := Unmarshal(&C)
if err != nil {t.Fatalf("unable to decode into struct, %v", err)
}
您可能需要将viper中保存的所有设置变为字符串,而不是将它们写入文件。您可以使用您喜欢的格式的marshaller和返回的配置AllSettings()
。
import (yaml "gopkg.in/yaml.v2"// ...
) func yamlStringSettings() string {c := viper.AllSettings()bs, err := yaml.Marshal(c)if err != nil {t.Fatalf("unable to marshal config to YAML: %v", err)}return string(bs)
}
Viper or Vipers?
Viper随时可以使用。开始使用Viper无需配置或初始化。由于大多数应用程序都希望使用单个中央存储库进行配置,因此viper软件包提供了此功能。它类似于单身人士。
使用多个Viper
您还可以创建许多不同的viper,以便在您的应用程序中使用。每个都有自己独特的配置和价值观。每个都可以从不同的配置文件,键值存储等中读取.viper包支持的所有功能都被镜像为viper上的方法。
x := viper.New()
y := viper.New()x.SetDefault("ContentDir", "content")
y.SetDefault("ContentDir", "foobar")
go_viper解析相关推荐
- spf13/viper
参考资料 仓库地址 https://github.com/spf13/viper Viper(毒蛇,蝰蛇)是Golang应用程序开源配置解决方案,包括12-Factor应用程序.旨在应用程序中处理各种 ...
- golang通过RSA算法生成token,go从配置文件中注入密钥文件,go从文件中读取密钥文件,go RSA算法下token生成与解析;go java token共用
RSA算法 token生成与解析 本文演示两种方式,一种是把密钥文件放在配置文件中,一种是把密钥文件本身放入项目或者容器中. 下面两种的区别在于私钥公钥的初始化, init方法,需要哪种取哪种. 通过 ...
- List元素互换,List元素转换下标,Java Collections.swap()方法实例解析
Java Collections.swap()方法解析 jdk源码: public static void swap(List<?> list, int i, int j) {// ins ...
- 条形码?二维码?生成、解析都在这里!
二维码生成与解析 一.生成二维码 二.解析二维码 三.生成一维码 四.全部的代码 五.pom依赖 直接上代码: 一.生成二维码 public class demo {private static fi ...
- Go 学习笔记(82)— Go 第三方库之 viper(解析配置文件、热更新配置文件)
1. viper 特点 viper 是一个完整的 Go应用程序的配置解决方案,它被设计为在应用程序中工作,并能处理所有类型的配置需求和格式.支持特性功能如下: 设置默认值 读取 JSON.TOML.Y ...
- Go 学习笔记(77)— Go 第三方库之 cronexpr(解析 crontab 表达式,定时任务)
cronexpr 支持的比 Linux 自身的 crontab 更详细,可以精确到秒级别. 1. 实现方式 cronexpr 表达式从前到后的顺序如下所示: 字段类型 是否为必须字段 允许的值 允 ...
- mybatis配置文件解析
mybatis配置文件解析 mybatis核心配置文件`mybatis-config.xml文件. mybatis的配置文件包含了会深深影响mybatis行为的设置和属性信息. 能配置的内容: con ...
- 谷歌BERT预训练源码解析(二):模型构建
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_39470744/arti ...
- Python 标准库之 xml.etree.ElementTree xml解析
Python 标准库之 xml.etree.ElementTree Python中有多种xml处理API,常用的有xml.dom.*模块.xml.sax.*模块.xml.parser.expat模块和 ...
最新文章
- php提交表单关闭弹出层,使用js实现关闭js弹出层的窗口
- mysql提示performance_schema缺表
- 面向接口编程详解(一)—— 思想基础
- 从程序语言排行榜来解读IT及Web的发展
- 数字图像处理实验(7):PROJECT 04-03 , Lowpass Filtering
- str 类常用的函数
- 数据中心绿色新技术的探讨
- Errors running builder 'DeploymentBuilder' on project '工程名'
- mpvue v-html解决方案,mpvue开发小程序所遇问题及h5转化方案
- 使用多行sql字符串时,要注意不要忽略了空格
- C++:11---友元函数、友元类
- Eclipse手动配置svn
- 最新版Spring Cloud Alibaba微服务架构-Openfeign服务调用篇
- Android:Smali语法中文介绍
- ASP.NET MVC 5 默认模板的JS和CSS 是怎么加载的?
- cherry mx board 1.0 TLK键盘使用手册
- XCEL查找SQL SERVER数据库的数据
- 电子护照阅读器|酒店机场高铁自助机录入系统
- ppt在服务器上打开要修复,打开ppt提示需要修复怎么办-处理ppt总是提示需要修复的方法 - 河东软件园...
- python写excel宏_使用python执行excel的VBA(宏)
热门文章
- 夕阳红旅游团第四周报告
- 这些手写代码会了吗?少年
- 【CSS 形状 (Shapes)】
- ⼩程序(微信)【面试】
- Swagger如何屏蔽某些接口显示
- Python爬虫的实际运用之:破解滑动验证码
- 李航(统计学习方法第四章)
- tomcat URL简写案例:模拟网站www.baidu.com的访问
- 字节流与字符流(FileInputStream类和FileOutputStream类)
- 怎么查看无线路由器连接的设备连接服务器,手机如何查看无线wifi连接人数 手机查看无线wifi连接人数方法【介绍】...