配置文件时每个项目中不可或缺的部分,我们平常用它来统一管理项目中redis
、mysql
、jwt
等所需要的基础配置。
配置文件有很多三方库支持,这里我们选择github.com/spf13/viper
,viper支持JSON、 TOML、YAML、HCL、INI等多种格式的配置文件,并且还可以监听文件的变化进行热更新
安装viper
go get github.com/spf13/viper
新增配置文件
创建文件config.yaml
:
app: # 应用基本配置
env: dev # 环境名称
port: 8082 # 服务监听端口号
name: eve # 应用名称
database:
driver: mysql # 数据库驱动
host: 127.0.0.1 # 域名
port: 3306 # 端口号
database: eve # 数据库名称
username: root # 用户名
password: 12345678 # 密码
charset: utf8mb4 # 编码格式
以上是我们正常使用的一个配置文件的格式,内容可以根据自己后续使用来自行配置
编写配置文件对应的结构体
我们希望我们的配置文件在项目中是高可读性的,那我们就可以用结构体来承载配置文件的值,这样在后续的使用中就比较方便
新增internal/config/app.go
:
package config
type App struct {
Name string
Port string
Env string
}
新增 internal/config/database.go
:
package config
type Database struct {
Driver string
Host string
Port string
User string
Password string
Database string
Charset string
}
注意: 这里配置的名称需要跟配置文件中的名称一致,也可以通过给结构体新增tag来达到配置文件和结构体名称不一致的目的,如:
type App struct {
AppName string `mapstructure:"name"`
AppPort string `mapstructure:"port"`
AppEnv string `mapstructure:"env"`
}
这样写也可以,不过为了提高可读性,我们不提倡这种写法
然后我们再新增一个配置文件集合,新增文件internal/config/config.go
:
// Config 配置文件集合
type Config struct {
App App
Database Database
}
配置文件载入方法
再修改internal/config/config.go
文件,新增一个读取配置的GetConfig
方法:
package config
import (
"eve/internal/tool"
"fmt"
"github.com/spf13/viper"
)
// Config 配置文件集合
type Config struct {
App App
Database Database
}
// GetConfig 读取配置文件
func GetConfig() (c *Config) {
// 获取项目的根目录
rootDir, _ := tool.GetRootDir()
// 实例化viper,并根据地址读取配置文件
v := viper.New()
v.SetConfigFile(rootDir + "/config.yaml")
err := v.ReadInConfig()
if err != nil {
fmt.Println("ReadInConfigError: ", err)
return
}
// 将读取到的配置文件绑定到返回参数c
err = v.Unmarshal(&c)
if err != nil {
fmt.Println("ConfigUnmarshalError: ", err)
return
}
return
}
同时为了获取项目根目录,在eve/internal
下新增了一个tool
工具库,新增eve/internal/tool/tool.go
文件:
package tool
import (
"os"
"path/filepath"
)
func GetRootDir() (string, error) {
wd, err := os.Getwd()
if err != nil {
return "", err
}
rootDir, err := filepath.Abs(wd)
if err != nil {
return "", err
}
return rootDir, nil
}
这样配置文件以及读取功能就完成了
全局变量
上边完成了配置文件的定义以及配置文件的读取,那在项目中如何使用呢?本次我们通过全局变量的形式给其他模块调用,创建internal/global/global.go
文件:
package global
import (
"eve/internal/config"
)
var (
Config *config.Config
)
上边在global.go
文件中创建了一个Config变量,但是还没有赋值,我们希望在项目启动时初始化配置文件以及其他基础模块(如mysql
、redis
),那就可以通过init方法,init方法在模块加载时会自动执行,创建internal/bootstrap/init.go
文件:
package bootstrap
import (
"eve/internal/config"
"eve/internal/global"
)
func init() {
// 初始化配置文件
global.Config = config.GetConfig()
}
在这个文件中,定义了init方法,方法中初始化了global.Config
变量,但是还没有执行,我们可以通过在入口文件中引入该文件的方式来让init方法执行,修改cmd/root.go
文件:
// Package cmd /*
package cmd
import (
_ "eve/internal/bootstrap"
"github.com/spf13/cobra"
"os"
)
...
注意看,这里只是在import
中新增了一行_ "eve/internal/bootstrap"
,这样项目用到的初始化工作就会在入口文件处完成,其他模块在使用时可以通过引入eve/internal/global
模块来直接使用
总结
- 安装viper
- 创建config.yaml配置文件
- 配置文件载入
- 新增工具模块
- 全局变量定义和初始化
commit-hash: 249c1431b