安装 Viper
go get github.com/spf13/viper
Viper 读取配置文件
viper.SetConfigFile("./config.yaml") // 指定配置文件路径
viper.SetConfigName("config") // 配置文件名称(无扩展名)
viper.SetConfigType("yaml") // 如果配置文件的名称中没有扩展名,则需要配置此项
viper.AddConfigPath("/etc/appname/") // 查找配置文件所在的路径
viper.AddConfigPath("$HOME/.appname") // 多次调用以添加多个搜索路径
viper.AddConfigPath(".") // 还可以在工作目录中查找配置
err := viper.ReadInConfig() // 查找并读取配置文件
if err != nil { // 处理读取配置文件的错误
panic(fmt.Errorf("Fatal error config file: %s \n", err))
}
以上方法很多,但只是为了更多的使用自由,我们可以直接指定访问的配置文件路径
viper.SetConfigFile("./config.yaml") // 指定配置文件路径
也可以多个方法来找到配置文件(多个文件且文件格式不同可能会使用到)。
viper.SetConfigName("config") // 配置文件名称(无扩展名)
viper.SetConfigType("yaml") // 如果配置文件的名称中没有扩展名,则需要配置此项
viper.AddConfigPath("./conf") // 查找配置文件所在的路径
在下面的情况下,如果同一个文件夹下面有./conf/config.yaml
和 ./conf/config.json
,viper
会优先选择 json
格式的配置文件
viper.SetConfigName("config") // 配置文件名称(无扩展名)
viper.AddConfigPath("./conf") // 查找配置文件所在的路径
Viper 热加载
如果在运行过程中更改配置文件,那么我们需要重新编译程序。幸好,Viper
为我们增加了热加载的功能。
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
// 配置文件发生变更之后会调用的回调函数
fmt.Println("Config file changed:", e.Name)
})
Viper 使用案例
yaml
格式的配置文件 config.yaml
mysql:
host: "127.0.0.1"
port: 3306
user: "root"
password: "123456jkld"
database: "user"
json
格式的配置文件 config.json
{
"mysql": {
"host": "127.0.0.1",
"port": 3306,
"user": "root",
"password": "123456jkld",
"database": "user"
}
}
main.go
package main
import (
"fmt"
"github.com/fsnotify/fsnotify"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"github.com/spf13/viper"
)
var DB *gorm.DB
func configInit() {
viper.SetConfigFile("./conf/config.yaml") // 指定配置文件路径
//viper.SetConfigFile("./conf/config.json")
err := viper.ReadInConfig() // 查找并读取配置文件
if err != nil { // 处理读取配置文件的错误
panic(fmt.Errorf("Fatal error config file: %s \n", err))
}
// 监控配置文件发生变化
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
// 配置文件发生变更之后会调用的回调函数
fmt.Println("Config file changed:", e.Name)
})
}
func mysqlInit() {
// viper 获取配置信息
user := viper.GetString("mysql.user")
password := viper.GetString("mysql.password")
host := viper.GetString("mysql.host")
port := viper.GetInt("mysql.port")
database := viper.GetString("mysql.database")
// 连接数据库
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local", user, password, host, port, database)
db, err := gorm.Open("mysql", dsn)
if err != nil {
panic(err)
}
// 赋值给全局变量
DB = db
}
func main() {
// 读取配置信息
configInit()
// 数据库连接初始化
mysqlInit()
// 以上任一环节出错都会报错
fmt.Println("Success!")
}
使用结构体变量保存配置信息
Viper
还支持将配置信息保存到自定义的结构体中,主要使用 Unmarshal(rawVal interface{}) : error
方法
config.yaml
introduction:
name: "test_project"
version: "0.0.1"
mysql:
host: "127.0.0.1"
port: 3306
user: "root"
password: "123456jkld"
database: "user"
main.go
package main
import (
"fmt"
"github.com/spf13/viper"
)
type Config struct {
*IntroductionConfig `mapstructure:"introduction"`
*MySQLConfig `mapstructure:"mysql"`
}
type IntroductionConfig struct {
Name string `mapstructure:"name"`
Version string `mapstructure:"version"`
}
type MySQLConfig struct {
Host string `mapstructure:"host"`
User string `mapstructure:"user"`
Password string `mapstructure:"password"`
DB string `mapstructure:"database"`
Port int `mapstructure:"port"`
}
var config = new(Config)
func main() {
viper.SetConfigFile("./conf/config.yaml") // 指定配置文件路径
err := viper.ReadInConfig() // 读取配置信息
if err != nil { // 读取配置信息失败
panic(fmt.Errorf("Fatal error config file: %s \n", err))
}
// 将读取的配置信息保存至全局变量 config
if err := viper.Unmarshal(config); err != nil {
panic(err)
}
fmt.Printf("%#v\n", *(config.MySQLConfig)) // main.MySQLConfig{Host:"127.0.0.1", User:"root", Password:"123456jkld", DB:"user", Port:3306}
fmt.Printf("%#v\n", *(config.IntroductionConfig)) // main.IntroductionConfig{Name:"test_project", Version:"0.0.1"}
}
记住,将配置信息解析到结构体中一定要使用 mapstructure
字段。