Viper:強大的Go配置解析庫

Hello-Brand發表於2024-08-20

1 介紹

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/下面建立四個資料夾 localdevbetaprod 四個資料夾,每個資料夾都有一個custom.yaml檔案,當 app.env 的值變化的時候,讀取的檔案也跟著變化,下面是local的資訊

white_list: 
  user_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 整體檔案結構如下

image

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

效果如下:
image

3 總結

Viper 是一個功能強大、簡潔、易於的 Go 配置庫,幫助開發者輕鬆管理應用程式的配置,並提供靈活的接入方式

相關文章