首页>>后端>>Golang->Golang名库观止

Golang名库观止

时间:2023-12-01 本站 点击:0

文章首发于公众号:程序员读书;欢迎关注,可以第一时间收到文章更新哦,转载本文请注明来源!

前言

对于现代应用程序,尤其大中型的项目来说,在程序启动和运行时,往往需要传入很多参数来控制程序的行为,这些参数可以通过以下几种方式传递给程序:

命令行参数

环境变量

配置文件

显然,对于Go项目而言,单个去读取命令行、环境变量、配置文件并不难,但一个个读取却是很麻烦,有没有一个第三方库可以帮我们一次性读取上面几种数据源的配置呢?

有的,这里推荐使用viper库,viper支持读取不同数据源和不同格式的配置文件,是Go项目读取配置的神器,今天跟着这篇文章,一起来探究一下吧!~

viper简介

viper是一个很完善的Go项目配置解决方案,很多著名的开源项目都在使用,比如Hugo,Docker都使用了该库,使用viper可以让我们专注于自己的项目代码,而不用自己写那些配置解析代码。

功能

支持配置key默认值设置

支持读取JSON,TOML,YAML,HCL,envfile和java properties等多种不同类型配置文件

可以监听配置文件的变化,并重新加载配置文件

读取系统环境变量的值

读取存储在远程配置中心的配置数据,如ectd,Consul,firestore等系统,并监听配置的变化

从命令行读取配置

从buffer读取配置

可以显示设置配置的值

viper配置优先级

viper支持从多个数据源读取配置值,因此当同一个配置key在多个数据源有值时,viper读取的优先级如下:

显示使用Set函数设置值

flag:命令行参数

env:环境变量

config:配置文件

key/value store:key/value存储系统,如(etcd)

default:默认值

优先级示意图

安装viper

viper的安装非常简单,如同其他Go第三方包一样,只需要go get命令即可安装,如:

安装

go get github.com/spf13/viper

使用

import "github.com/spf13/viper"

支持哪些文件格式

我们一直在说,viper支持多种不同格式的配置文件,到底是哪些格式呢?如下:

json

toml

yaml

yml

properties

props

prop

hcl

tfvars

dotenv

env

ini

key大小写问题

viper的配置的key值是不区分大小写,如:

# 小写的keyviper.set("test","this is a test value")# 大写的key,也可以读到值fmt.Println(viper.get("TEST"))//输出"this is a test value"

使用指南

在了解了viper是什么之后,下面我们来看看要怎么使用viper去帮我们读取配置。

如何访问viper的功能

使用包名viper,如:

viper.SetDefault("key1","value")//调用包级别下的函数

使用viper.New()函数创建一个Viper Struct,如:

viper := viper.New()viper.SetDefault("key2","value2")

其实,这就是Go包的编程惯例,对实现功能对象再进行封装,并通过包名来调用。

因此,下面所有示例中调用函数使用viper,可以是指包名viper,或者通过viper.New()返回的对象。

配置默认值

viper.SetDefault("key1","value1")viper.SetDefault("key2","value2")

读取配置文件

直接指定文件路径

viper.SetConfigFile("./config.yaml")viper.ReadInConfig()fmt.Println(viper.Get("test"))

多路径查找

viper.SetConfigName("config")     // 配置文件名,不需要后缀名viper.SetConfigType("yml")            // 配置文件格式viper.AddConfigPath("/etc/appname/")  // 查找配置文件的路径viper.AddConfigPath("$HOME/.appname") // 查找配置文件的路径viper.AddConfigPath(".")              // 查找配置文件的路径err := viper.ReadInConfig()           // 查找并读取配置文件if err != nil {                       // 处理错误    panic(fmt.Errorf("Fatal error config file: %w \n", err))}

读取配置文件时,可能会出现错误,如果我们想判断是否是因为找不到文件而报错的,可以判断err是否为ConfigFileNotFoundError

if err := viper.ReadInConfig(); err != nil {    if _, ok := err.(viper.ConfigFileNotFoundError); ok {    } else {    }}

写配置文件

除了读取配置文件外,viper也支持将配置值写入配置文件,viper提供了四个函数,用于将配置写回文件。

WriteConfig

WriteConfig函数会将配置写入预先设置好路径的配置文件中,如果配置文件存在,则覆盖,如果没有,则创建。

SafeWriteConfig

SafeWriterConfig与WriteConfig函数唯一的不同是如果配置文件存在,则会返回一个错误。

WriteConfigAs

WriteConfigAs与WriteConfig函数的不同是需要传入配置文件保存路径,viper会根据文件后缀判断写入格式。

SafeWriteConfigAs

SafeWriteConfigAs与WriteConfigAs的唯一不同是如果配置文件存在,则返回一个错误。

监听配置文件

viper支持监听配置文件,并会在配置文件发生变化,重新读取配置文件和回调函数,这样可以避免每次配置变化时,都需要重启启动应用的麻烦。

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

从io.Reader读取配置

除了支持从配置文件读取配置外,viper也支持从实现了io.Reader接口的实例中读取配置(其实配置文件也实现了io.Reader),如:

import "github.com/spf13/viper"0

显示设置配置项

也可以使用Set函数显示为某个key设置值,这种方式的优先级最高,会覆盖该key在其他地方的值,如:

import "github.com/spf13/viper"1

注册和使用别名

为某个配置key设置别名,这样可以方便我们在不改变key的情况下,使用别的名称访问该配置。

import "github.com/spf13/viper"2

读取环境变量

对于读取操作系统环境变量,viper提供了下面五个函数:

AutomaticEnv()

BindEnv(string...) : error

SetEnvPrefix(string)

SetEnvKeyReplacer(string...) *strings.Replacer

AllowEmptyEnv(bool)

要让viper读取环境变量,有两种方式:

调用AutomaticEnv函数,开启环境变量读取

import "github.com/spf13/viper"3

使用BindEnv绑定某个环境变量

import "github.com/spf13/viper"4

使用函数SetEnvPrefix可以为所有环境变量设置一个前缀,这个前缀会影响AutomaticEnvBindEnv函数

import "github.com/spf13/viper"5

环境变量大多是使用下划号(_)作为分隔符的,如果想替换,可以使用SetEnvKeyReplacer函数,如:

import "github.com/spf13/viper"6

默认的情况下,如果读取到的环境变量值为空(注意,不是环境变量不存在,而是其值为空),会继续向优化级更低数据源去查找配置,如果想阻止这一行为,让空的环境变量值有效,则可以调用AllowEmptyEnv函数:

import "github.com/spf13/viper"7

与命令行参数搭配使用

viper可以和解析命令行库相关flag库一起工作,从命令行读取配置,其内置了对pflag库的支持,同时也留有接口让我们可以支持扩展其他的flag库

pflag

import "github.com/spf13/viper"8

扩展其他flag

如果我们没有使用pflag库,但又想让viper帮我们读取命令行参数呢?

import "github.com/spf13/viper"9

远程key/value存储支持

viper支持存储或者读取远程配置存储中心和NoSQL(目前支持etcd,Consul,firestore)的配置,并可以实时监听配置的变化,不过需要在代码中引入下面的包:

# 小写的keyviper.set("test","this is a test value")# 大写的key,也可以读到值fmt.Println(viper.get("TEST"))//输出"this is a test value"0

现在远程配置中心存储着以下JSON的配置信息

# 小写的keyviper.set("test","this is a test value")# 大写的key,也可以读到值fmt.Println(viper.get("TEST"))//输出"this is a test value"1

那么我们可以通过下面的方面连接到系统,并读取配置,也可以单独开启一个Goroutine实时监听配置的变化。

连接Consul

# 小写的keyviper.set("test","this is a test value")# 大写的key,也可以读到值fmt.Println(viper.get("TEST"))//输出"this is a test value"2

连接etcd

# 小写的keyviper.set("test","this is a test value")# 大写的key,也可以读到值fmt.Println(viper.get("TEST"))//输出"this is a test value"3

连接firestore

# 小写的keyviper.set("test","this is a test value")# 大写的key,也可以读到值fmt.Println(viper.get("TEST"))//输出"this is a test value"4

连接上配置中心后,就可以像读取配置文件读取其中的配置了,如:

# 小写的keyviper.set("test","this is a test value")# 大写的key,也可以读到值fmt.Println(viper.get("TEST"))//输出"this is a test value"5

监听配置系统,如:

# 小写的keyviper.set("test","this is a test value")# 大写的key,也可以读到值fmt.Println(viper.get("TEST"))//输出"this is a test value"6

另外,viper连接etcd,Consul,firestore进行配置传输时,也支持加解密,这样可以更加安全,如果想要实现加密传输可以把AddRemoteProvider函数换为SecureRemoteProvider

# 小写的keyviper.set("test","this is a test value")# 大写的key,也可以读到值fmt.Println(viper.get("TEST"))//输出"this is a test value"7

访问配置

viper可以帮我们读取各个地方的配置,那读到配置之后,要怎么用呢?

直接访问

# 小写的keyviper.set("test","this is a test value")# 大写的key,也可以读到值fmt.Println(viper.get("TEST"))//输出"this is a test value"8

对于多层级配置key,可以用逗号隔号,如:

# 小写的keyviper.set("test","this is a test value")# 大写的key,也可以读到值fmt.Println(viper.get("TEST"))//输出"this is a test value"9

数组,可以用序列号访问,如:

viper.SetDefault("key1","value")//调用包级别下的函数0

也可以使用sub函数解析某个key的下级配置,如:

viper.SetDefault("key1","value")//调用包级别下的函数1

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

序列化

读取了配置之后,除了使用上面列举出来的函数访问配置,还可以将配置序列化到struct或map之中,这样可以更加方便访问配置。

示例代码

配置文件:config.yaml

viper.SetDefault("key1","value")//调用包级别下的函数2

解析代码:

viper.SetDefault("key1","value")//调用包级别下的函数3

对于多层级的配置,viper也支持序列化到一个复杂的struct中,如:

我们将config.yaml改为如下结构:

viper.SetDefault("key1","value")//调用包级别下的函数4

示例程序

viper.SetDefault("key1","value")//调用包级别下的函数5

判断配置key是否存在

viper.SetDefault("key1","value")//调用包级别下的函数6

打印所有配置

viper.SetDefault("key1","value")//调用包级别下的函数7

小结

好了,文章写到了这里,已经很长了,相信如果看到这里的话,你应该对viper有非常详细的了解,文章如果有写的不对的地方或者有什么需要补充的地方,欢迎留言讨论!

原文:https://juejin.cn/post/7096416508054044685


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Golang/5874.html