go语言中的配置管理神器 --viper 一(一)

简介: go语言中的配置管理神器 --viper 一

viper

Viper是什么?

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

  • 默认配置
  • 从 JSON, TOML, YAML, HCL 和 Java 属性配置文件读取数据
  • 实时查看和重新读取配置文件(可选)
  • 从环境变量中读取
  • 从远程配置系统(etcd 或 Consul)读取数据并监听变化
  • 从命令行参数读取
  • 从 buffer 中读取
  • 设置显式值

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

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

  • explicit call to Set
  • flag
  • env
  • config
  • key/value store
  • default
  • Viper配置键不区分大小写。

建立默认值

viper.SetDefault("ContentDir", "content")
viper.SetDefault("LayoutDir", "layouts")
viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})

读取配置文件

Viper 需要极少的配置让它知道去哪里查找配置文件。Viper 支持 JSON, TOML, YAML, HCL 和 Java 属性配置文件。Viper 可以搜索多个路径,但目前单个 Viper 实例仅 支持单个配置文件。Viper 不默认任何配置搜索路径,将默认决策留给应用程序。

viper.SetConfigName("config") // 配置文件的名字,不包括拓展名
viper.AddConfigPath("/etc/appname/")   // 添加配置文件的路径
viper.AddConfigPath("$HOME/.appname")  // 多次调用以添加多个搜索路径
viper.AddConfigPath(".")               // .代表当前项目的工作目录
err := viper.ReadInConfig() //查找读取配置文件
if err != nil { // Handle errors reading the config file
    panic(fmt.Errorf("Fatal error config file: %s \n", err))
}

监听和重新读取配置文件

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

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

确保在调用 WatchConfig() 之前添加所有的配置路径 ConfigPath

viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
    fmt.Println("Config file changed:", e.Name)
})

从 io.Reader 读取配置

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

viper.SetConfigType("yaml") // or viper.SetConfigType("YAML")
// any approach to require this configuration into your program.
var yamlExample = []byte(`
Hacker: true
name: steve
hobbies:
- skateboarding
- snowboarding
- go
clothing:
  jacket: leather
  trousers: denim
age: 35
eyes : brown
beard: true
`)
viper.ReadConfig(bytes.NewBuffer(yamlExample))
viper.Get("name") 

覆盖设置

这些可以来自命令行标志,也可以来自你自己的应用程序逻辑。

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 完全支持环境变量。这使得 12 factor 应用程序可以开箱即用。 五种方法可以帮助使用 ENV:

AutomaticEnv()
BindEnv(string...) : error
SetEnvPrefix(string)
SetEnvKeyReplacer(string...) *strings.Replacer
AllowEmptyEnvVar(bool)

在处理环境变量时,重要的是要认识到 Viper 将环境变量视为区分大小写的变量。

Viper 提供了一种机制来确保 ENV 变量是唯一的。通过使用 SetEnvPrefix,可以告诉 Viper 在读取环境变量时使用前缀。BindEnv 和 AutomaticEnv 都将使用此前缀。

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

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

AutomaticEnv 是一个强大的帮手,特别是与 SetEnvPrefix 结合使用时。每当发出 viper.Get 请求时,Viper 都会检查环境变量。它将适用以下规则。 它将检查一个环境变量,其名称与大写的键匹配,如果设置了 EnvPrefix,则以它为前缀。

SetEnvKeyReplacer 允许你使用 strings.Replacer 对象来重写 Env 键。如果你想在 Get() 调用中使用 - 或者某些东西,但希望你的环境变量使用 _ 分隔符, 这是很有用的。使用它的一个例子可以在 viper_test.go 中找到。

默认情况下,空环境变量被视为未设置,并将回退到下一个配置源。要设置空环境变量,请使用 AllowEmptyEnv 方法。

SetEnvPrefix("spf") // 将自动大写
BindEnv("id")
os.Setenv("SPF_ID", "13") 
id := Get("id") // 13

用Flags

Viper 具有绑定到标志的能力。具体来说,Viper支持Cobra库中使用的Pflag。

与BindEnv类似,该值不是在调用绑定方法时设置的,而是在访问该方法时设置的。这意味着你可以根据需要尽早进行绑定,即使在init()函数中也是如此。

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

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

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

举个例子:

pflag.Int("flagname", 1234, "help message for flagname")
pflag.Parse()
viper.BindPFlags(pflag.CommandLine)
i := viper.GetInt("flagname") // 从viper而不是从pflag检索值

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

例如:

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 检索值
  ...
}

从Viper获取值

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

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{}

需要认识到的一件重要事情是,每一个Get方法在找不到值的时候都会返回零值。为了检查给定的键是否存在,提供了IsSet()方法。

例如:

viper.GetString("logfile") // 不区分大小写的设置和获取
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
        }
    }
}

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

GetString("datastore.metric.host") // (返回 "127.0.0.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”) // 返回 “0.0.0.0”


go语言中的配置管理神器 --viper 一(二)https://developer.aliyun.com/article/1391730

相关文章
|
9天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
29 2
|
7天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
18 2
|
7天前
|
Go C++
go语言中的条件语句
【11月更文挑战第4天】
20 2
|
7天前
|
Go
go语言中的 跳转语句
【11月更文挑战第4天】
15 4
|
7天前
|
JSON 安全 Go
Go语言中使用JWT鉴权、Token刷新完整示例,拿去直接用!
本文介绍了如何在 Go 语言中使用 Gin 框架实现 JWT 用户认证和安全保护。JWT(JSON Web Token)是一种轻量、高效的认证与授权解决方案,特别适合微服务架构。文章详细讲解了 JWT 的基本概念、结构以及如何在 Gin 中生成、解析和刷新 JWT。通过示例代码,展示了如何在实际项目中应用 JWT,确保用户身份验证和数据安全。完整代码可在 GitHub 仓库中查看。
38 1
|
9天前
|
Go 调度 开发者
探索Go语言中的并发模式:goroutine与channel
在本文中,我们将深入探讨Go语言中的核心并发特性——goroutine和channel。不同于传统的并发模型,Go语言的并发机制以其简洁性和高效性著称。本文将通过实际代码示例,展示如何利用goroutine实现轻量级的并发执行,以及如何通过channel安全地在goroutine之间传递数据。摘要部分将概述这些概念,并提示读者本文将提供哪些具体的技术洞见。
|
6月前
|
开发框架 安全 中间件
Go语言开发小技巧&易错点100例(十二)
Go语言开发小技巧&易错点100例(十二)
75 1
|
20天前
|
Go 数据安全/隐私保护 开发者
Go语言开发
【10月更文挑战第26天】Go语言开发
33 3
|
21天前
|
Java 程序员 Go
Go语言的开发
【10月更文挑战第25天】Go语言的开发
28 3
|
3月前
|
JSON 中间件 Go
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
本文详细介绍了如何在Go项目中集成并配置Zap日志库。首先通过`go get -u go.uber.org/zap`命令安装Zap,接着展示了`Logger`与`Sugared Logger`两种日志记录器的基本用法。随后深入探讨了Zap的高级配置,包括如何将日志输出至文件、调整时间格式、记录调用者信息以及日志分割等。最后,文章演示了如何在gin框架中集成Zap,通过自定义中间件实现了日志记录和异常恢复功能。通过这些步骤,读者可以掌握Zap在实际项目中的应用与定制方法
135 1
go语言后端开发学习(四) —— 在go项目中使用Zap日志库