Go语言项目中使用Viper获取配置信息详解
作者:仍沫
Viper是Go应用的完整配置解决方案,它能处理所有类型的配置需求和配置格式,支持:
- 设置默认值。
- 读取JSON、TOML、YAML、HCL、envfile和Java属性配置文件。
- 实时观察和重新读取配置(可选)。
- 读取环境变量。
- 从远程配置系统(etcd或Consul)读取配置,并观察其变化。
- 从命令行标志读取配置。
- 从缓冲区读取配置。
- 设置显式值。
Viper的优先级顺序是:显式调用Set
> 命令行标志 > 环境变量 > 配置文件 > 键/值 存储(etcd或Consul) > 默认值。
本文主要记录从yaml文件、环境变量中获取配置。
使用的go的版本和viper的版本如下:
go 1.20 github.com/spf13/viper v1.18.2
从配置文件中获取配置
执行以下指令初始化项目:
go mod init github.com/rengmo/practicego
执行以下语句安装viper包:
go get github.com/spf13/viper
创建yaml文件config/dev.yaml
,内容如下:
redis: host: localhost port: 6379 user: # 本地redis的用户名为空 password: abc123 db: 0
创建Go文件infrastructure/config.go
,内容如下:
package config import ( "fmt" "github.com/spf13/viper" ) func init() { // 设置配置文件的名字 viper.SetConfigName("dev") // 设置文件的格式 viper.SetConfigType("yaml") // 设置查找配置文件的路径为当前路径 . 表示项目的工作目录,也就是main.go同级的那个目录 viper.AddConfigPath("./config") // 读取配置文件中的数据到viper中 err := viper.ReadInConfig() if err != nil { panic(err) } // 从viper中获取配置数据 redisPort := viper.Get("redis.port") fmt.Printf("redisPort: %v \n", redisPort) // 打印结果:redisPort: 6379 }
还可以使用GetInt()、GetString()
等方法,获取指定类型的数据,viper.GetString("redis.port")
就是获取字符串类型的数据。
创建main.go
文件,内容如下:
package main import ( _ "github.com/rengmo/practicego/infrastructure" ) func main() { }
运行代码,会打印出获取到的端口号。
把
// 设置配置文件的名字 viper.SetConfigName("dev") // 设置文件的格式 viper.SetConfigType("yaml") // 设置查找配置文件的路径为当前路径 . 表示项目的工作目录,也就是main.go同级的那个目录 viper.AddConfigPath("./config")
换成:
// 设置配置文件的路径 viper.SetConfigFile("./config/dev.yaml")
同样能取到配置文件中的数据。
除了使用Get
方法viper.Get("redis.port")
获取配置数据,还可以将配置数据反序列化成Go对象。
func init() { ... var config *Config err = viper.Unmarshal(&config) if err != nil { panic(err) } redisConfig := config.Redis fmt.Printf("redisConfig %+v\n", redisConfig) // 打印的结果:redisConfig {Host:localhost Port:6379 User: Password:abc123 DB:0} } type Config struct { Redis RedisConfig } type RedisConfig struct { Host string Port int User string Password string DB int }
Viper对于配置项的键是不区分大小写的,比如把yaml文件中的键改成首字母大写:
Redis: Host: localhost Port: 6379
使用viper.Get("redis.port")
一样能获取到配置的值,使用viper.Get("REDIS.PORT")
同样能获取配置的值。
从环境变量中获取配置
AutomaticEnv
会检查环境变量中是否有和已经存在的键匹配的环境变量,如果有,就会把环境变量加载到viper中。
// AutomaticEnv makes Viper check if environment variables match any of the existing keys // (config, default or flags). If matching env vars are found, they are loaded into Viper. func AutomaticEnv() { v.AutomaticEnv() }
先在终端执行指令添加环境变量: export env=PROD
,然后在终端执行go run .
。
光看这个函数名称,是自动将环境变量添加到viper中的意思,那么执行下面的语句应该就能获取环境变量,但是无效:
viper.AutomaticEnv() env := viper.Get("env") fmt.Println("env: ", env) // env: <nil>
根据函数注释,需要确认viper中是否已经有对应的键,那么执行下面的语句应该就能获取环境变量,但是依然无效:
viper.SetDefault("env", "DEV") viper.AutomaticEnv() env := viper.Get("env") fmt.Println("env: ", env) // env: DEV
找了一下源码,判断键是否存在的地方使用了envkeys, exists := v.env[lcaseKey]
,而BindEnv
方法中有设置v.env
:
func (v *Viper) BindEnv(input ...string) error { if len(input) == 0 { return fmt.Errorf("missing key to bind to") } key := strings.ToLower(input[0]) if len(input) == 1 { v.env[key] = append(v.env[key], v.mergeWithEnvPrefix(key)) } else { v.env[key] = append(v.env[key], input[1:]...) } return nil }
所以需要这样使用:
viper.BindEnv("env", "DEV") viper.AutomaticEnv() env := viper.Get("env") fmt.Println("env: ", env) // env: PROD
要注意在比较过程中,Viper会把key转换成大写字母与环境变量进行比较,所以环境变量的名称必须为大写,不能这样设置环境变量:export env=PROD
,必须这样设置环境变量:export ENV=PROD
。
其他
如果是使用编辑器来运行代码,需要在编辑器中设置环境变量,我用的是VSCode编辑器,所以是在launch.json
中添加了环境变量:
{ // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "Launch Package", "type": "go", "request": "launch", "mode": "auto", "program": "${workspaceFolder}", "env": { "env": "PROD" } } ] }
序列化和反序列化时,可以使用 mapstructure
指定键的名称。
比如yaml文件内容:
mysql: host: localhost port: 3306 user: root password: 666666Aa_ db_name: practicego
go文件内容:
type Config struct { Redis RedisConfig MySQL MySQLConfig Priority string } type MySQLConfig struct { Host string Port int User string Password string DBName string `mapstructure:"db_name"` } func init() { viper.SetConfigFile("./config/dev.yaml") err := viper.ReadInConfig() if err != nil { panic(err) } var config *Config err = viper.Unmarshal(&config) if err != nil { panic(err) } mysqlConfig := config.MySQL fmt.Printf("mysqlConfig %+v\n", mysqlConfig) }
以上就是Go语言项目中使用Viper获取配置信息详解的详细内容,更多关于Go Viper获取配置信息的资料请关注脚本之家其它相关文章!