GoLang實現(xiàn)Viper庫的封裝流程詳解
Viper是什么
Viper是一個用于Go語言應(yīng)用程序的配置管理庫。它提供了一種簡單而靈活的方式來處理應(yīng)用程序的配置,支持多種格式的配置文件,并提供了一組API來讀取和使用這些配置。
Viper支持多種配置文件格式,包括JSON、TOML、YAML和HCL等。它還支持環(huán)境變量和命令行標志等配置方式。這使得Viper非常適合需要在不同環(huán)境中運行(如開發(fā)、測試和生產(chǎn)環(huán)境)的應(yīng)用程序,因為可以使用不同的配置文件和設(shè)置來管理應(yīng)用程序的行為。 優(yōu)點:使用Viper,可以輕松地將配置信息加載到應(yīng)用程序中,并在需要時獲取這些信息。Viper還提供了一些方便的功能,例如默認值、類型轉(zhuǎn)換和鍵名重映射等,使得配置管理變得更加簡單和靈活。
實現(xiàn)Viper的封裝
在根目錄下創(chuàng)建一個core文件,然后在core文件中創(chuàng)建多一個interal文件,這個interal
文件的方法僅能讓core里進行調(diào)用的,一般可以將一些僅給core內(nèi)方法使用并且是需要封裝的方法放置在內(nèi)(調(diào)取internal包中的方法不需要添加core包名 )。如圖大概就是這樣的,然后就是定義一個viper的interface
,實現(xiàn)內(nèi)部的GetFile
和GetFiles
兩個方法,前者是配置信息,后者是文件夾路徑。當然我們也可以使用embed
這樣方式實現(xiàn),但是最好本地也實現(xiàn)一個比較穩(wěn)妥一點!
interal文件夾代碼實現(xiàn)
core/interal/viper_interface.go
type IViper interface { // GetFile 獲取文件信息 GetFile(path, filename string) io.Reader // GetFiles 獲取配置文件夾信息 GetFiles(dir string) ([]fs.DirEntry, error) }
core/interal/viper.go
var Viper = new(viper) type viper struct{} func (v *viper) GetFile(path, filename string) io.Reader { file, err := os.Open(filepath.Join(path, filename)) if err != nil { return nil } defer func() { _ = file.Close() }() all, err := io.ReadAll(file) if err != nil { return nil } return bytes.NewReader(all) } func (v *viper) GetFiles(dir string) ([]os.DirEntry, error) { entries, err := os.ReadDir(dir) if err != nil { return nil, errors.Wrapf(err, "[viper][path:%s]獲取配置文件夾信息失敗!", dir) } return entries, nil }
core/interal/vuper_embed.go (實現(xiàn)本地embed標記,當然推薦使用下面本地實現(xiàn)的方法)
var Viper = new(viper) type viper struct{} func (v *viper) GetFile(path, filename string) io.Reader { file, err := global.Configs.Open(filepath.Join(path, filename)) if err != nil { fmt.Printf("[viper][path:%s][filename:%s]文件不存在!\n", path, filename) return nil } return file } func (v *viper) GetFiles(dir string) ([]fs.DirEntry, error) { entries, err := global.Configs.ReadDir(dir) if err != nil { return nil, errors.Wrapf(err, "[viper][embed][dir:%s]獲取配置文件夾信息失敗!", dir) } return entries, nil }
core/viper.go
我這里的config文件夾中的配置yaml格式如:gorm.debug.yaml
var Viper = new(_viper) type _viper struct{} // Initialization . // 優(yōu)先級: 命令行 > 環(huán)境變量 > 默認值 func (c *_viper) Initialization(path ...string) { var configs string if len(path) == 0 { flag.StringVar(&configs, "c", "", "choose configs dir.") flag.Parse() if configs == "" { env := os.Getenv(internal.ConfigsEnv) if env == "" { // 判斷 internal.ConfigEnv 常量存儲的環(huán)境變量是否為空 configs = internal.ConfigsPath fmt.Printf("您正在使用配置默認文件夾:%s,configs的文件夾路徑為%s\n", internal.ConfigsPath, configs) } else { configs = env fmt.Printf("您正在使用%s環(huán)境變量,configs的文件夾路徑為%s\n", internal.ConfigsEnv, configs) } } else { // 命令行參數(shù)不為空 將值賦值于configs fmt.Printf("您正在使用命令行的-c參數(shù)傳遞的值,configs的文件夾路徑為%s\n", configs) } } else { // path 這個切片大于0,取第一個值賦值到configs configs = path[0] } v := viper.New() v.AddConfigPath(configs) entries, err := internal.Viper.GetFiles(configs) if err != nil { fmt.Printf("%+v\n", err) return } for i := 0; i < len(entries); i++ { if entries[i].IsDir() { // 忽略配置文件夾里的文件夾 continue } filename := entries[i].Name() // 分割文件名 names := strings.Split(filename, ".") if len(names) == 3 { config := names[0] // 文件名 mode := names[1] // 模式 yaml := names[2] // 文件后綴 if mode != gin.Mode() { continue } // 拼接 v.SetConfigName(strings.Join([]string{config, mode}, ".")) v.SetConfigType(yaml) reader := internal.Viper.GetFile(configs, filename) err = v.MergeConfig(reader) if err != nil { fmt.Printf("[viper][filename:%s][err:%v]配置文件讀取失敗!\n", filename, err) return } // 讀取配置文件 err = v.ReadInConfig() if err != nil { fmt.Printf("[viper][filename:%s][err:%v]配置文件讀取失敗!\n", filename, err) continue } // 反序列化config err = v.Unmarshal(&global.Config) if err != nil { fmt.Printf("[viper][err:%v]反序列化失敗!\n", err) continue } v.OnConfigChange(func(in fsnotify.Event) { fmt.Printf("[viper][filename:%s]配置文件更新\n", in.Name) err = v.Unmarshal(&global.Config) if err != nil { fmt.Printf("[viper][err:%v]反序列化失敗!\n", err) } }) v.WatchConfig() } } // 注冊到全局 global.Viper = v }
根目錄下創(chuàng)建embed.go
如果在自己練習(xí)的時候已在編輯器中配置了這個embed標記可以忽略上述本地的viper_embed.go
文件(如下圖配置所示),但是建議不忽略上述的viper_embed.go
文件
package main // 這些有import導(dǎo)報 // import (......) func init() { global.Configs = configs } var ( //go:embed configs configs embed.FS )
global中引入結(jié)構(gòu)體
global/global.go
var ( Viper *viper.Viper )
到此這篇關(guān)于GoLang實現(xiàn)Viper庫的封裝流程詳解的文章就介紹到這了,更多相關(guān)GoLang Viper庫封裝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang實現(xiàn)讀取excel數(shù)據(jù)并導(dǎo)入數(shù)據(jù)庫
Go 語言是一門適合用于編寫高效且并發(fā)的 Web 應(yīng)用程序的編程語言,同時也可以使用它進行數(shù)據(jù)處理和分析,本文主要介紹了如何通過go語言實現(xiàn)讀取excel數(shù)據(jù)并導(dǎo)入數(shù)據(jù)庫,感興趣的小伙伴可以了解下2025-04-04Go語言設(shè)計模式之實現(xiàn)觀察者模式解決代碼臃腫
今天學(xué)習(xí)一下用?Go?實現(xiàn)觀察者模式,觀察者模式主要是用來實現(xiàn)事件驅(qū)動編程。事件驅(qū)動編程的應(yīng)用還是挺廣的,除了我們都知道的能夠用來解耦:用戶修改密碼后,給用戶發(fā)短信進行風險提示之類的典型場景,在微服務(wù)架構(gòu)實現(xiàn)最終一致性、實現(xiàn)事件源A?+?ES2022-08-08golang利用函數(shù)閉包實現(xiàn)簡單的中間件
中間件設(shè)計模式是一種常見的軟件設(shè)計模式,它在許多編程語言和框架中被廣泛應(yīng)用,這篇文章主要為大家介紹一下golang利用函數(shù)閉包實現(xiàn)一個簡單的中間件,感興趣的可以了解下2023-10-10