什么是Viper?

Viper是一个Go应用程序完整的配置文件解决方案,包括12-Factor应用程序。它被设计为:在应用程序中工作,可以处理所有类型的配置需求和格式。它支持:

  • 设置默认值
  • 从JSON,TOML,YAML,HCL和Java属性配置文件中读取
  • 实时观看和重新读取配置文件(可选)
  • 从环境变量中读取
  • 从远程配置系统(etcd或Consul)读取,并观察变化
  • 从命令行标志读取
  • 从缓冲区读取
  • 设置显式值

Viper可以被认为是所有应用程序配置需求的注册表。

为何选择Viper?

构建现代应用程序时,你不必担心配置文件格式,只需专注于构建给力的软件。Viper就是为此提供帮助的。

Viper为你做了以下事情:

  1. 查找、加载和解析以JSON,TOML,YAML,HCL或Java属性格式的配置文件。
  2. 提供一种机制,来为不同的配置选项设置默认值。
  3. 提供一种机制,来为通过命令行标志指定的选项设置覆盖值。
  4. 提供别名系统,轻松重命名参数,而不会破坏现有代码。
  5. 与默认值相同时,可以很容易地区分其来源于命令行或配置文件。

Viper使用以下优先顺序。每个项目优先于其下方的项目:

使用Viper设置默认值

  • explicit call to Set
  • flag
  • env
  • config
  • key/value store
  • default
  1. viper.SetDefault("ContentDir", "content")

  2. viper.SetDefault("LayoutDir", "layouts")

  3. viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})

Viper读取配置文件

Viper需要最少的配置,因此它知道在哪里查找配置文件。Viper支持JSON,TOML,YAML,HCL和Java Properties文件。Viper可以搜索多个路径,但目前单个Viper实例仅支持单个配置文件。Viper不会默认使用任何配置搜索路径,而是将默认值决定应用于应用程序。

以下是如何使用Viper搜索和读取配置文件的示例。不需要任何特定路径,但应在预期配置文件的位置提供至少一个路径。

  1. viper.SetConfigName("config") // name of config file (without extension)

  2. viper.AddConfigPath("/etc/appname/") // path to look for the config file in

  3. viper.AddConfigPath("$HOME/.appname") // call multiple times to add many search paths

  4. viper.AddConfigPath(".") // optionally look for config in the working directory

  5. err := viper.ReadInConfig() // Find and read the config file

  6. if err != nil { // Handle errors reading the config file

  7. panic(fmt.Errorf("Fatal error config file: %s \n", err))

  8. }

监听并重新读取配置文件

Viper支持在运行时让应用程序实时读取配置文件。

需要重新启动服务器以使配置生效的日子已经一去不复返了,viper驱动的应用程序可以在运行时读取配置文件的更新,而不会错过任何一个节拍。

只需告诉viper实例watchConfig即可。您可以选择为Viper提供每次发生更改时运行的功能。

确保在调用之前添加所有configPath WatchConfig()

  1. viper.WatchConfig()

  2. viper.OnConfigChange(func(e fsnotify.Event) {

  3. fmt.Println("Config file changed:", e.Name)

  4. })

从io.Reader读取配置

Viper预定义了许多配置源,例如文件,环境变量,标志和远程K / V存储,但您不受它们的约束。您还可以实现自己的必需配置源并将其提供给viper。

  1. viper.SetConfigType("yaml") // 或viper.SetConfigType(“YAML”)

  2. //任何需要将此配置放入程序的方法

  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")

Viper设置并覆盖配置值

  1. viper.Set("Verbose", true)

  2. viper.Set("LogFile", LogFile)

Viper注册和使用别名

别名允许多个键引用单个值

  1. viper.RegisterAlias("loud", "Verbose")

  2. viper.Set("verbose", true) // same result as next line

  3. viper.Set("loud", true) // same result as prior line

  4. viper.GetBool("loud") // true

  5. viper.GetBool("verbose") // true

Viper使用环境变量

Viper完全支持环境变量。有四种方法可以帮助使用ENV:

  1. AutomaticEnv()

  2. BindEnv(string...) : error

  3. SetEnvPrefix(string)

  4. SetEnvKeyReplacer(string...) *strings.Replacer

BindEnv需要一个或两个参数。第一个参数是键名,第二个是环境变量的名称。环境变量的名称区分大小写。如果未提供ENV变量名,则Viper将自动假设密钥名称与ENV变量名称匹配,但ENV变量为IN ALL CAPS。当您明确提供ENV变量名称时,它不会自动添加前缀。

使用ENV变量时要认识到的一件重要事情是每次访问时都会读取该值。Viper在BindEnv调用时不会修复该值。

AutomaticEnv尤其是当与结合了强大的帮手 SetEnvPrefix。调用时,Viper将在任何viper.Get请求发出时检查环境变量。它将适用以下规则。它将检查一个环境变量,其名称与大写的键匹配,并以EnvPrefix前缀。

SetEnvKeyReplacer允许您使用strings.Replacer对象重写Env键到一定程度。如果要-Get()调用中使用或使用某些内容 ,但希望环境变量使用_分隔符,则此选项非常有用。可以在中找到使用它的示例viper_test.go

ENV实例

  1. SetEnvPrefix("spf") //将自动大写

  2. BindEnv("id")

  3. os.Setenv("SPF_ID", "13") // 通常在应用以外完成

  4. id := Get("id") // 13

使用flag

Viper能够绑定到flag。

就像BindEnv,在调用绑定方法时,不会设置该值。这意味着您可以尽早绑定,甚至可以在init()函数中绑定 。

对于单个标志,该BindPFlag()方法提供此功能。

  1. serverCmd.Flags().Int("port", 1138, "Port to run Application server on")

  2. viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))

您还可以绑定一组现有的pflags(pflag.FlagSet)

  1. pflag.Int("flagname", 1234, "help message for flagname")

  2. pflag.Parse()

  3. viper.BindPFlags(pflag.CommandLine)

  4. i := viper.GetInt("flagname")

在Viper中使用pflag并不排除使用 标准库中使用标志包的其他包。pflag包可以通过导入这些标志来处理为标志包定义的标志。这是通过调用名为AddGoFlagSet()的pflag包提供的便利函数来实现的。

  1. package main

  2. import (

  3. "flag"

  4. "github.com/spf13/pflag"

  5. )

  6. func main() {

  7. // using standard library "flag" package

  8. flag.Int("flagname", 1234, "help message for flagname")

  9. pflag.CommandLine.AddGoFlagSet(flag.CommandLine)

  10. pflag.Parse()

  11. viper.BindPFlags(pflag.CommandLine)

  12. i := viper.GetInt("flagname") // retrieve value from viper

  13. ...

  14. }

flag接口

如果您不使用,Viper提供两个Go接口来绑定其他标志系统Pflags

FlagValue代表一个标志。这是一个关于如何实现此接口的非常简单的示例:

  1. type myFlag struct {}

  2. func (f myFlag)HasChanged()bool { return false }

  3. func (f myFlag)Name()string { return “ my-flag-name ” }

  4. func (f myFlag)ValueString()string { return “ my -flag-value “ }

  5. 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 。

  1. $ go get github.com/xordataexchange/crypt/bin/crypt

  2. $ crypt set -plaintext /config/hugo.json /Users/hugo/settings/config.json

确认您的值已设置:

$ crypt get -plaintext /config/hugo.json

远程key/value存储示例 - 未加密

  1. viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json")

  2. viper.SetConfigType("json") //因为字节流中没有文件扩展名,支持的扩展名是“json”,“toml”,“yaml”,“yml”,“properties”,“props”,“prop”

  3. err := viper.ReadRemoteConfig()

远程key/value存储示例 - 加密

  1. viper.AddSecureRemoteProvider("etcd","http://127.0.0.1:4001","/config/hugo.json","/etc/secrets/mykeyring.gpg")

  2. viper.SetConfigType("json") //因为字节流中没有文件扩展名,支持的扩展名是“json”,“toml”,“yaml”,“yml”,“properties”,“props”,“prop”

  3. err := viper.ReadRemoteConfig()

监听etcd中的变化 - 未加密

  1. //或者,您可以创建一个新的viper实例

  2. var runtime_viper = viper.New()

  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. //解密配置

  8. runtime_viper.Unmarshal(&runtime_conf)

  9. // 打开一个goroutine来永远监听远程变化

  10. go func(){

  11. for {

  12. time.Sleep(time.Second * 5) // 每次请求后延迟

  13. err := runtime_viper.WatchRemoteConfig()

  14. if err != nil {

  15. log.Errorf("unable to read remote config: %v", err)

  16. continue

  17. }

  18. //将新配置解组到我们的运行时配置结构中。您还可以使用通道

  19. //实现信号以通知系统更改

  20. runtime_viper.Unmarshal(&runtime_conf)

  21. }

  22. }()

Viper获取值

在Viper中,有几种方法可以根据值的类型获取值。存在以下功能和方法:

  1. Get(key string) : interface{}

  2. GetBool(key string) : bool

  3. GetFloat64(key string) : float64

  4. GetInt(key string) : int

  5. GetString(key string) : string

  6. GetStringMap(key string) : map[string]interface{}

  7. GetStringMapString(key string) : map[string]string

  8. GetStringSlice(key string) : []string

  9. GetTime(key string) : time.Time

  10. GetDuration(key string) : time.Duration

  11. IsSet(key string) : bool

  12. AllSettings() : map[string]interface{}

如果找不到,每个Get函数都将返回零值。IsSet()方法检查给定密钥是否存在。

实例:

  1. viper.GetString("logfile") // case-insensitive Setting & Getting

  2. if viper.GetBool("verbose") {

  3. fmt.Println("verbose enabled")

  4. }

访问嵌套

访问器方法也接受深层嵌套键的格式化路径。例如,如果加载了以下JSON文件:

  1. {

  2. "host": {

  3. "address": "localhost",

  4. "port": 5799

  5. },

  6. "datastore": {

  7. "metric": {

  8. "host": "127.0.0.1",

  9. "port": 3099

  10. },

  11. "warehouse": {

  12. "host": "198.0.0.1",

  13. "port": 2112

  14. }

  15. }

  16. }

Viper可以通过传递.分隔的键路径来访问嵌套字段:

GetString("datastore.metric.host") // (returns "127.0.0.1")

这符合上面建立的优先规则; 搜索路径将在剩余的配置注册表中级联,直到找到。

例如,给定此配置文件,都datastore.metric.host和 datastore.metric.port已经定义(并且可以被覆盖)。如果另外datastore.metric.protocol在默认值中定义,Viper也会找到它。

但是,如果使用立即值datastore.metric覆盖(通过标志,环境变量,Set()方法,...),则所有子键 datastore.metric变为未定义,它们将被更高优先级的配置级别“遮蔽”。

最后,如果存在与分隔的键路径匹配的键,则将返回其值。例如

  1. {

  2. "datastore.metric.host": "0.0.0.0",

  3. "host": {

  4. "address": "localhost",

  5. "port": 5799

  6. },

  7. "datastore": {

  8. "metric": {

  9. "host": "127.0.0.1",

  10. "port": 3099

  11. },

  12. "warehouse": {

  13. "host": "198.0.0.1",

  14. "port": 2112

  15. }

  16. }

  17. }

  18. GetString("datastore.metric.host") // returns "0.0.0.0"

提取sub-tree

例如

  1. app:

  2. cache1:

  3. max-items: 100

  4. item-size: 64

  5. cache2:

  6. max-items: 200

  7. item-size: 80

  8. #执行后

  9. subv := viper.Sub("app.cache1")

  10. #subv为

  11. max-items:100

  12. item-size:64

假设

func NewCache(cfg *Viper) *Cache {...}

它根据格式化为的配置信息创建缓存subv。现在可以轻松地分别创建这两个缓存:

  1. cfg1 := viper.Sub("app.cache1")

  2. cache1 := NewCache(cfg1)

  3. cfg2 := viper.Sub("app.cache2")

  4. cache2 := NewCache(cfg2)

遍历

您还可以选择Unmarshaling all或特定值到struct,map等。

有两种方法可以做到这一点:

  1. Unmarshal(rawVal interface{}) : error

  2. UnmarshalKey(key string, rawVal interface{}) : error

例如:

  1. type config struct {

  2. Port int

  3. Name string

  4. PathMap string `mapstructure:"path_map"`

  5. }

  6. var C config

  7. err := Unmarshal(&C)

  8. if err != nil {

  9. t.Fatalf("unable to decode into struct, %v", err)

  10. }

转为字符串

您可能需要将viper中保存的所有设置变为字符串,而不是将它们写入文件。您可以使用您喜欢的格式的marshaller和返回的配置AllSettings()

  1. import (

  2. yaml "gopkg.in/yaml.v2"

  3. // ...

  4. )

  5. func yamlStringSettings() string {

  6. c := viper.AllSettings()

  7. bs, err := yaml.Marshal(c)

  8. if err != nil {

  9. t.Fatalf("unable to marshal config to YAML: %v", err)

  10. }

  11. return string(bs)

  12. }

Viper or Vipers?

Viper随时可以使用。开始使用Viper无需配置或初始化。由于大多数应用程序都希望使用单个中央存储库进行配置,因此viper软件包提供了此功能。它类似于单身人士。

在上面的所有示例中,他们演示了使用viper的单例式方法。

使用多个Viper

您还可以创建许多不同的viper,以便在您的应用程序中使用。每个都有自己独特的配置和价值观。每个都可以从不同的配置文件,键值存储等中读取.viper包支持的所有功能都被镜像为viper上的方法。

例如

  1. x := viper.New()

  2. y := viper.New()

  3. x.SetDefault("ContentDir", "content")

  4. y.SetDefault("ContentDir", "foobar")

使用多viper时,用户可以跟踪不同的viper。

尊重别人劳动成果,原文地址:

https://blog.csdn.net/cs380637384/article/details/81217767

github.com/spf13/viper go viper包介绍相关推荐

  1. GitHub开源项目 - Jeecg-Boot开始开发平台介绍

    GitHub开源项目 - Jeecg-Boot开始开发平台介绍 Jeecg-Boot 是一款基于SpringBoot+代码生成器的快速开发平台!采用前后端分离架构:SpringBoot,Mybatis ...

  2. go语言negroni包介绍

    go语言negroni包介绍 前言 go语言很好地支持了网络编程,go 语言与web 框架相关的包有很多,本文主要介绍go语言的negroni包. 前置参考博客:HTTP 协议 与 golang we ...

  3. golang办公工作流workflow js-ojus/flow包介绍——系列一

    golang语言的办公工作流的包介绍--系列一 golang办公工作流workflow利用js-ojus/flow做测试--系列二 golang办公流程引擎初体验js-ojus/flow--系列三 g ...

  4. 工具分享 | linemap-快速绘制山峦地图的R可视化包介绍

    公众号后台回复"图书",了解更多号主新书内容 作者:宁海涛 来源:DataCharm 上一次介绍了Python绘制svg的优秀可视化库Pygal,今天我们介绍一下一个优秀的R地图可 ...

  5. 安装软件包的三种方法、rpm包介绍、rpm工具用法、yum工具用法、yum搭建本地仓库...

    为什么80%的码农都做不了架构师?>>>    安装软件包的三种方法 rpm工具 yum工具 源码包 rpm rpm命令是RPM软件包的管理工具.rpm原本是Red Hat Linu ...

  6. 7.1 安装软件包的三种方法 7.2 rpm包介绍 7.3 rpm工具用法 7.4 yum工具用法 7.5 yum搭建本地仓库...

    7.1 安装软件包的三种方法 7.2 rpm包介绍 7.3 rpm工具用法 7.4 yum工具用法 7.5 yum搭建本地仓库 三种方法 rpm工具----->类型windows下的exe程序 ...

  7. java中的jsonjar_java中使用json之相关jar包介绍

    1.JSON产生的背景 Web开发过程中,在客户端与服务器之间离不开数据的交互,这就需要规定交互数据的相关格式,通常来说都是使用JSON来传递数据. 2.JSON对象以及JSON字符串 JSON对象和 ...

  8. Spring目录结构和基础JAR包介绍

    目前 Spring 框架的最新版本是 5.1.8,本教程是基于 Spring 的稳定版本 3.2.13 进行讲解的.读者可以通过网址 http://repo.spring.io/simple/libs ...

  9. 《PHP挖宝》2—Symfony包介绍

    <PHP挖宝>2-Symfony包介绍 文章目录 <PHP挖宝>2-Symfony包介绍 Hello World示例 Symfony使用的包 部分Symfony包介绍 < ...

最新文章

  1. 解决'ping' 不是内部或外部命令,也不是可运行的程序
  2. TensorFlow 笔记6--迁移学习
  3. 在iOS8 下用Swift 创建自定义的键盘
  4. Android studio导入support-v4.jar
  5. api自动化_如何在不增加人员的情况下自动化API安全程序
  6. 树莓派搭建私人服务器
  7. paip.注册java程序为LINUX系统服务的总结。
  8. 单片机矩阵键盘扫描程序c语言,51单片机矩阵键盘扫描程序(源代码)
  9. 【专项测试】京东“安全测试”
  10. 图像特征提取:Sobel边缘检测
  11. 常见计算机病毒有些什么症状,电脑中病毒的症状有哪些
  12. 编码至高法则-高内聚低耦合
  13. ros入门--中科院软件所ros学习笔记
  14. 计算机毕业设计SSM大学生社团管理系统【附源码数据库】
  15. 安装wpa_supplicant工具
  16. 回滚机制有多少种?它们的实现原理是什么?这些你确定都知道?
  17. 数商云:以数字化全面促进传统产业升级,纺织行业最大限度实现精益管理
  18. 最新计算机学术研讨会,TC预告|CCF 2020第十届全国文字与计算学术研讨会
  19. PC客户端(C/S架构)测试点整理
  20. Lind.DDD.Messaging框架通讯组件介绍

热门文章

  1. 函数分离常数法 oracle,函数值域之《分离常数法》正确打开方式
  2. Unity DOTS简明教程
  3. xp系统打印机服务器win7连接不了,xp不能访问win7共享打印机
  4. python 用selenium获取好友空间说说及时间写入txt
  5. 网站api自己怎么写_网站seo优化中文章标题怎么写?
  6. linux c 时间微秒,linux下C语言获取微秒级时间
  7. 火车头分页post php,轻松搞定PHPCMS V9火车头采集自动分页
  8. freeCodeCamp “使用 CSS 和 HTML 创建更复杂的形状”练习-----创建“爱心”❤️形状
  9. android小游戏源码拼图,android编写的数字拼图游戏(带详细注释)
  10. SEO快排系统功能更新