一個小例子,給你講透 Go 配置管理,輕鬆將其融入到項目中

在軟件開發中,配置管理是一個不可或缺的部分。無論是開發環境、測試環境還是生產環境,我們都需要一種方法來存儲和讀取配置信息。

在 Golang 項目中,Viper 是一個非常流行且功能強大的庫,用於處理配置文件。下面我會寫一些例子,幫助大家快速上手。

什麼是 Viper?

不賣關子,直接上 GitHub 地址:https://github.com/spf13/viper 大家可以直接去看 README.md

我簡單的描述下,Viper 是一個 Go 語言的配置管理庫,它提供了簡單而強大的方式來處理應用程序的配置需求。無論是從文件、環境變量還是遠程配置中獲取配置信息,Viper 都能搞定。

如何使用 Viper?

安裝

在終端中運行以下命令:

go get github.com/spf13/viper

基本用法

以下是一個簡單的示例,展示如何讀取配置文件:

package main

import (
 "fmt"
 "github.com/spf13/viper"
)

func main() {
 // 設置配置文件名稱(不包括文件擴展名)
 viper.SetConfigName("config")

 // 設置配置文件類型
 viper.SetConfigType("toml")

 // 添加配置文件搜索路徑
 viper.AddConfigPath(".")

 // 讀取配置文件
 err := viper.ReadInConfig()
 if err != nil {
  panic(fmt.Errorf("fatal error config file: %w", err))
 }

 // 獲取配置項
 message := viper.GetString("message")
 fmt.Println("Message:", message)
}

配置文件示例(config.toml)

message = "Hello, Viper!"

輸出

Message: Hello, Viper!

這只是一個基本的用法,但在實際項目開發中,推薦採用綁定到配置結構體的方法。

業務場景

場景一

例如,在涉及 MySQL 和 Redis 的項目中,可能需要在配置文件中設置用戶名和密碼。這時,採用結構體綁定配置的方法比較清晰,可以參考如下示例。

package main

import (
 "fmt"
 "github.com/spf13/viper"
 "log"
)

type configStructs struct {
 MySQL struct {
  Username string `toml:"username"`
  Password string `toml:"password"`
 } `toml:"mysql"`

 Redis struct {
  Username string `toml:"username"`
  Password string `toml:"password"`
 } `toml:"redis"`
}

func main() {
 // 設置配置文件名稱(不包括文件擴展名)
 viper.SetConfigName("config")

 // 設置配置文件類型
 viper.SetConfigType("toml")

 // 添加配置文件搜索路徑
 viper.AddConfigPath(".")

 // 讀取配置文件
 err := viper.ReadInConfig()
 if err != nil {
  log.Fatal(fmt.Errorf("fatal error config file: %w", err))
 }

 // 將配置文件解析到結構體
 configs := new(configStructs)
 err = viper.Unmarshal(configs)
 if err != nil {
  log.Fatal(fmt.Errorf("fatal error config file: %w", err))
 }

 fmt.Println("MySQL-Username:", configs.MySQL.Username)
 fmt.Println("MySQL-Password:", configs.MySQL.Password)
 fmt.Println("Redis-Username:", configs.Redis.Username)
 fmt.Println("Redis-Password:", configs.Redis.Password)
}

配置文件示例(config.toml)

[mysql]
    username = "mysql"
    password = "mysql_qwerty"

[redis]
    username = "redis"
    password = "redis_qwerty"

輸出:

MySQL-Username: mysql
MySQL-Password: mysql_qwerty
Redis-Username: redis
Redis-Password: redis_qwerty

場景二

例如,目標是發佈一個包含所有必需配置的獨立二進制包,而不將配置文件暴露在項目頂層目錄。我們應該如何將配置文件嵌入到二進制文件中,確保它們在運行時可以被正確訪問?

改造起來不麻煩,可參考如下示例。

package main

import (
 "bytes"
 _ "embed"
 "fmt"
 "github.com/spf13/viper"
 "log"
)

type configStructs struct {
 MySQL struct {
  Username string `toml:"username"`
  Password string `toml:"password"`
 } `toml:"mysql"`

 Redis struct {
  Username string `toml:"username"`
  Password string `toml:"password"`
 } `toml:"redis"`
}

var (
 //go:embed config.toml
 configFile []byte
)

func main() {
 // 設置配置文件名稱(不包括文件擴展名)
 viper.SetConfigName("config")

 // 設置配置文件類型
 viper.SetConfigType("toml")

 // 添加配置文件搜索路徑
 viper.AddConfigPath(".")

 // 讀取配置文件
 err := viper.ReadConfig(bytes.NewReader(configFile))
 if err != nil {
  log.Fatal(fmt.Errorf("fatal error config file: %w", err))
 }

 // 將配置文件解析到結構體
 configs := new(configStructs)
 err = viper.Unmarshal(configs)
 if err != nil {
  log.Fatal(fmt.Errorf("fatal error config file: %w", err))
 }

 fmt.Println("MySQL-Username:", configs.MySQL.Username)
 fmt.Println("MySQL-Password:", configs.MySQL.Password)
 fmt.Println("Redis-Username:", configs.Redis.Username)
 fmt.Println("Redis-Password:", configs.Redis.Password)
}

輸出:

MySQL-Username: mysql
MySQL-Password: mysql_qwerty
Redis-Username: redis
Redis-Password: redis_qwerty

代碼封裝

目前,示例代碼都是直接在 main 函數中編寫的。

爲了提高代碼的可維護性和可重用性,我們將這些配置相關的代碼封裝成一個獨立的 configs 包。

package configs

import (
 "bytes"
 _ "embed"
 "fmt"
 "github.com/spf13/viper"
 "log"
)

// ConfigStructs 定義了配置文件的結構
type ConfigStructs struct {
 MySQL struct {
  Username string `toml:"username"`
  Password string `toml:"password"`
 } `toml:"mysql"`

 Redis struct {
  Username string `toml:"username"`
  Password string `toml:"password"`
 } `toml:"redis"`
}

var (
 // 配置結構體的實例
 config = new(ConfigStructs)

 //go:embed config.toml
 configFile []byte
)

func init() {
 // 設置配置文件名稱(不包括文件擴展名)
 viper.SetConfigName("config")

 // 設置配置文件類型
 viper.SetConfigType("toml")

 // 添加配置文件搜索路徑
 viper.AddConfigPath(".")

 // 讀取配置文件
 err := viper.ReadConfig(bytes.NewReader(configFile))
 if err != nil {
  log.Fatal(fmt.Errorf("fatal error config file: %w", err))
 }

 // 將配置文件解析到結構體
 err = viper.Unmarshal(config)
 if err != nil {
  log.Fatal(fmt.Errorf("fatal error config file: %w", err))
 }
}

// Get 獲取配置項
func Get() ConfigStructs {
 return *config
}

使用 configs 包:

import (
 "項目名稱/pkg/configs"
 "fmt"
)

// 獲取配置
fmt.Println("MySQL-Username:", configs.Get().MySQL.Username)
fmt.Println("MySQL-Password:", configs.Get().MySQL.Password)
fmt.Println("Redis-Username:", configs.Get().Redis.Username)
fmt.Println("Redis-Password:", configs.Get().Redis.Password)

輸出:

MySQL-Username: mysql
MySQL-Password: mysql_qwerty
Redis-Username: redis
Redis-Password: redis_qwerty

到這,相信已經對 Viper 有了全面的瞭解,並能夠在自己的 Go 項目中靈活應用。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/W62zvlzu1rmfARE_Is7zzQ