Viper:強大的 Go 配置解析庫
1 介紹
Viper (https://github.com/spf13/viper) 是適用於 Go 應用程序的完整配置解決方案。它被設計用於在應用程序中工作,並且可以處理所有類型的配置需求和格式。目前 Star 26.6k, 它支持以下特性:
-
設置默認值
-
從 JSON、TOML、YAML、HCL、envfile 和 Java properties 格式的配置文件讀取配置信息
-
實時監控和重新讀取配置文件(可選)
-
從環境變量中讀取
-
從遠程配置系統(etcd 或 Consul)讀取並監控配置變化
-
從命令行參數讀取配置
-
從 buffer 讀取配置
-
顯式配置值
2 Golang 項目中的使用
2.1 在 go 中安裝 Viper
# 終端中輸入如下命令
ArchitePlus@MacBook-Air traffic.demo % go get github.com/spf13/viper
2.2 編寫通用配置文件
因爲能支持多重配置文件格式,包含 JSON、TOML、YAML、HCL、INI、envfile 和 Java 屬性文件,方便開發者根據項目需求選擇合適的格式。
我們這邊使用 yaml 做示例。
創建一個conf
文件夾,添加子文件夾files
,然後在下面添加config.yaml
,裏面可以放一些基本的、通用的配置信息。
app: # 應用基本配置
env: local # 環境名稱
port: 8888 # 服務監聽端口號
app_name: traffic-demo # 應用名稱
app_url: http://localhost # 應用訪問地址
MySQL: # MySQL配置
host: 127.0.0.1 # MySQL主機地址
port: 3306 # MySQL端口號
user: root # MySQL用戶名
password: <PASSWORD>
db_name: traffic # MySQL數據庫名
可以看到,我們有兩個配置信息,一個是 app,一個是 MySQL。
2.3 編寫用戶自定義配置文件
還有一些用戶自定義的配置文件 (可能有多個), 是需要根據不同的運行環境(local、dev、beta、prod) 來進行區分的. 所以我們在config/files/
下面創建四個文件夾 local
、dev
、beta
、prod
四個文件夾, 每個文件夾都有一個custom.yaml
文件, 當 app.env
的值變化的時候, 讀取的文件也跟着變化, 下面是 local 的信息
white_list:
user_id: # 用戶Id列表
- 063105015
- 063105024
- 063105028
request_path: # 訪問路徑
- /api/v1/users
- /api/v1/ops
2.4 配置映射的結構體
我們需要配置結構體(實體對象)來映射這倆配置,這樣的話,後面在調用的時候非常方便。
在conf
文件夾下面添加子文件夾model
,存放解析映射的結構體,這邊新增一個config.go
和一個custom.go
文件,內容如下:
2.4.1 config.go
package config
// 配置文件解析彙總
type Configuration struct {
App App `mapstructure:"app" json:"app" yaml:"app"`
MYSQL MYSQL `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
}
// 配置文件解析:app
type App struct {
Env string `mapstructure:"env" json:"env" yaml:"env"`
Port string `mapstructure:"port" json:"port" yaml:"port"`
AppName string `mapstructure:"app_name" json:"app_name" yaml:"app_name"`
AppUrl string `mapstructure:"app_url" json:"app_url" yaml:"app_url"`
}
// 配置文件解析:mysql
type MYSQL struct {
Host string `mapstructure:"host" json:"host" yaml:"host"`
Port string `mapstructure:"poet" json:"port" yaml:"port"`
User string `mapstructure:"user" json:"user" yaml:"user"`
Password string `mapstructure:"password" json:"password" yaml:"password"`
DbName string `mapstructure:"db_name" json:"db_name" yaml:"db_name"`
}
2.4.2 custom.go
package config
type Custom struct {
WhiteList whiteList `mapstructure:"white_list" json:"white_list" yaml:"white_list"`
}
// 配置文件解析彙總
type whiteList struct {
UserId []string `mapstructure:"user_id" json:"user_id" yaml:"user_id"`
RequestPath []string `mapstructure:"request_path" json:"request_path" yaml:"request_path"`
}
2.5 創建 Global 全局變量解析
新建一個 global/app.go
文件,定義 Application 結構體,用來存放一些項目啓動時的變量,方便調用。
目前先將 viper 結構體和 Configuration 結構體放入,後續會陸續添加其他配置信息。
package global
import (
"github.com/spf13/viper"
config "traffic.demo/config/model"
)
// 定義一個全局的Application
type Application struct {
ConfigViper *viper.Viper
Config config.Configuration
Custom config.Custom
}
// 初始化Application
var App = new(Application)
2.5 關鍵步驟:結構體映射邏輯
配置文件要映射到結構體,這樣才能把配置數據提取出來,這邊創建 bootstrap/config.go
文件,作爲核心解析代碼的載體,代碼如下 (代碼中的解釋已經很清楚了):
package bootstrap
import (
"fmt"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
"traffic.demo/global"
)
// configAssemble 是一個泛型函數,用於組裝配置文件並返回 viper.Viper 指針
//
// 參數:
//
// configPath string - 配置文件路徑
// viperStruct T - 用來接收配置文件的結構體
//
// 返回值:
//
// *viper.Viper - viper.Viper 指針
func configAssemble[T any](configPath string, viperStruct T) *viper.Viper {
// 初始化 viper
v := viper.New()
// 配置文件地址
v.SetConfigFile(configPath)
// 配置文件類型,yaml
v.SetConfigType("yaml")
if err := v.ReadInConfig(); err != nil {
panic(fmt.Errorf("read config failed: %s \n", err))
}
// 監聽配置文件
v.WatchConfig()
v.OnConfigChange(func(in fsnotify.Event) {
fmt.Println("config file changed:", in.Name)
// 重載配置 &global.App.Config
if err := v.Unmarshal(viperStruct); err != nil {
fmt.Println(err)
}
})
// 將配置賦值給全局變量 &global.App.Config
if err := v.Unmarshal(viperStruct); err != nil {
fmt.Println(err)
}
return v
}
// InitializeConfig 初始化配置函數
func InitializeConfig() {
// 全局應用文件配置路徑,這邊是我們的具體global config文件地址
config := "conf/files/config.yaml"
configAssemble(config, &global.App.Config)
// 用戶自定義的配置(根據不同的運行環境,加載不同的配置文件)
customConfig := fmt.Sprintf("%s%s%s", "conf/files/", global.App.Config.App.Env, "/custom.yaml")
configAssemble(customConfig, &global.App.Custom)
}
2.6 整體文件結構如下
2.7 運行結果
main.go 代碼如下:
package main
import (
"fmt"
"traffic.demo/global"
)
// main 函數是程序的入口點
func main() {
bootstrap.InitializeConfig()
fmt.Println("Traffic Service Started...!")
var globalCong = global.App.Config
fmt.Printf("globalCong: %+v\n", globalCong)
var customCong = global.App.Custom
fmt.Printf("customCong: %+v\n", customCong)
}
效果如下:
3 總結
Viper 是一個功能強大、簡潔、易於的 Go 配置庫,幫助開發者輕鬆管理應用程序的配置,並提供靈活的接入方式
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/LL9EUOaKthTP6-i2zBKykQ