Go語(yǔ)言項(xiàng)目中使用Viper獲取配置信息詳解
Viper是Go應(yīng)用的完整配置解決方案,它能處理所有類型的配置需求和配置格式,支持:
- 設(shè)置默認(rèn)值。
- 讀取JSON、TOML、YAML、HCL、envfile和Java屬性配置文件。
- 實(shí)時(shí)觀察和重新讀取配置(可選)。
- 讀取環(huán)境變量。
- 從遠(yuǎn)程配置系統(tǒng)(etcd或Consul)讀取配置,并觀察其變化。
- 從命令行標(biāo)志讀取配置。
- 從緩沖區(qū)讀取配置。
- 設(shè)置顯式值。
Viper的優(yōu)先級(jí)順序是:顯式調(diào)用Set
> 命令行標(biāo)志 > 環(huán)境變量 > 配置文件 > 鍵/值 存儲(chǔ)(etcd或Consul) > 默認(rèn)值。
本文主要記錄從yaml文件、環(huán)境變量中獲取配置。
使用的go的版本和viper的版本如下:
go 1.20 github.com/spf13/viper v1.18.2
從配置文件中獲取配置
執(zhí)行以下指令初始化項(xiàng)目:
go mod init github.com/rengmo/practicego
執(zhí)行以下語(yǔ)句安裝viper包:
go get github.com/spf13/viper
創(chuàng)建yaml文件config/dev.yaml
,內(nèi)容如下:
redis: host: localhost port: 6379 user: # 本地redis的用戶名為空 password: abc123 db: 0
創(chuàng)建Go文件infrastructure/config.go
,內(nèi)容如下:
package config import ( "fmt" "github.com/spf13/viper" ) func init() { // 設(shè)置配置文件的名字 viper.SetConfigName("dev") // 設(shè)置文件的格式 viper.SetConfigType("yaml") // 設(shè)置查找配置文件的路徑為當(dāng)前路徑 . 表示項(xiàng)目的工作目錄,也就是main.go同級(jí)的那個(gè)目錄 viper.AddConfigPath("./config") // 讀取配置文件中的數(shù)據(jù)到viper中 err := viper.ReadInConfig() if err != nil { panic(err) } // 從viper中獲取配置數(shù)據(jù) redisPort := viper.Get("redis.port") fmt.Printf("redisPort: %v \n", redisPort) // 打印結(jié)果:redisPort: 6379 }
還可以使用GetInt()、GetString()
等方法,獲取指定類型的數(shù)據(jù),viper.GetString("redis.port")
就是獲取字符串類型的數(shù)據(jù)。
創(chuàng)建main.go
文件,內(nèi)容如下:
package main import ( _ "github.com/rengmo/practicego/infrastructure" ) func main() { }
運(yùn)行代碼,會(huì)打印出獲取到的端口號(hào)。
把
// 設(shè)置配置文件的名字 viper.SetConfigName("dev") // 設(shè)置文件的格式 viper.SetConfigType("yaml") // 設(shè)置查找配置文件的路徑為當(dāng)前路徑 . 表示項(xiàng)目的工作目錄,也就是main.go同級(jí)的那個(gè)目錄 viper.AddConfigPath("./config")
換成:
// 設(shè)置配置文件的路徑 viper.SetConfigFile("./config/dev.yaml")
同樣能取到配置文件中的數(shù)據(jù)。
除了使用Get
方法viper.Get("redis.port")
獲取配置數(shù)據(jù),還可以將配置數(shù)據(jù)反序列化成Go對(duì)象。
func init() { ... var config *Config err = viper.Unmarshal(&config) if err != nil { panic(err) } redisConfig := config.Redis fmt.Printf("redisConfig %+v\n", redisConfig) // 打印的結(jié)果: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對(duì)于配置項(xiàng)的鍵是不區(qū)分大小寫的,比如把yaml文件中的鍵改成首字母大寫:
Redis: Host: localhost Port: 6379
使用viper.Get("redis.port")
一樣能獲取到配置的值,使用viper.Get("REDIS.PORT")
同樣能獲取配置的值。
從環(huán)境變量中獲取配置
AutomaticEnv
會(huì)檢查環(huán)境變量中是否有和已經(jīng)存在的鍵匹配的環(huán)境變量,如果有,就會(huì)把環(huán)境變量加載到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() }
先在終端執(zhí)行指令添加環(huán)境變量: export env=PROD
,然后在終端執(zhí)行go run .
。
光看這個(gè)函數(shù)名稱,是自動(dòng)將環(huán)境變量添加到viper中的意思,那么執(zhí)行下面的語(yǔ)句應(yīng)該就能獲取環(huán)境變量,但是無(wú)效:
viper.AutomaticEnv() env := viper.Get("env") fmt.Println("env: ", env) // env: <nil>
根據(jù)函數(shù)注釋,需要確認(rèn)viper中是否已經(jīng)有對(duì)應(yīng)的鍵,那么執(zhí)行下面的語(yǔ)句應(yīng)該就能獲取環(huán)境變量,但是依然無(wú)效:
viper.SetDefault("env", "DEV") viper.AutomaticEnv() env := viper.Get("env") fmt.Println("env: ", env) // env: DEV
找了一下源碼,判斷鍵是否存在的地方使用了envkeys, exists := v.env[lcaseKey]
,而BindEnv
方法中有設(shè)置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
要注意在比較過(guò)程中,Viper會(huì)把key轉(zhuǎn)換成大寫字母與環(huán)境變量進(jìn)行比較,所以環(huán)境變量的名稱必須為大寫,不能這樣設(shè)置環(huán)境變量:export env=PROD
,必須這樣設(shè)置環(huán)境變量:export ENV=PROD
。
其他
如果是使用編輯器來(lái)運(yùn)行代碼,需要在編輯器中設(shè)置環(huán)境變量,我用的是VSCode編輯器,所以是在launch.json
中添加了環(huán)境變量:
{ // 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" } } ] }
序列化和反序列化時(shí),可以使用 mapstructure
指定鍵的名稱。
比如yaml文件內(nèi)容:
mysql: host: localhost port: 3306 user: root password: 666666Aa_ db_name: practicego
go文件內(nèi)容:
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語(yǔ)言項(xiàng)目中使用Viper獲取配置信息詳解的詳細(xì)內(nèi)容,更多關(guān)于Go Viper獲取配置信息的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Golang 標(biāo)準(zhǔn)庫(kù) tips之waitgroup詳解
本篇文章給大家介紹Golang 標(biāo)準(zhǔn)庫(kù) tips之waitgroup的相關(guān)知識(shí),包括使用 channel 實(shí)現(xiàn) WaitGroup 的功能介紹,感興趣的朋友跟隨小編一起看看吧2021-07-07更高效的GoLevelDB:shardingdb實(shí)現(xiàn)分片和并發(fā)讀寫操作
這篇文章主要介紹了更高效的GoLevelDB:shardingdb實(shí)現(xiàn)分片和并發(fā)讀寫操作的相關(guān)資料,需要的朋友可以參考下2023-09-09使用go net實(shí)現(xiàn)簡(jiǎn)單的redis通信協(xié)議
本文主要介紹了go net實(shí)現(xiàn)簡(jiǎn)單的redis通信協(xié)議,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12解決Goland 提示 Unresolved reference 錯(cuò)誤的問(wèn)題
這篇文章主要介紹了解決Goland 提示 Unresolved reference 錯(cuò)誤的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12golang基礎(chǔ)之字符串與int、int64類型互相轉(zhuǎn)換
這篇文章主要給大家介紹了關(guān)于golang基礎(chǔ)之字符串與int、int64類型互相轉(zhuǎn)換的相關(guān)資料,在Go語(yǔ)言中string轉(zhuǎn)int是一項(xiàng)常見(jiàn)的操作,需要的朋友可以參考下2023-07-07Go語(yǔ)言異步API設(shè)計(jì)的扇入扇出模式詳解
這篇文章主要為大家介紹了Go語(yǔ)言異步API設(shè)計(jì)的扇入扇出模式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08