在软件开发中,配置管理是一个不可或缺的部分。无论是开发环境、测试环境还是生产环境,我们都需要一种方法来存储和读取配置信息。
在 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 项目中灵活应用。