引言
Viper是Go应用程序的完整配置解决方案,包括 12-Factor 应用程序。它设计用于在应用程序中工作,可以处理所有类型的配置需求和格式。它支持:
- 设置默认值
- 读取JSON、TOML、YAML、HCL、envfile和Java properties属性配置文件
- 实时查看和重读配置文件(可选)
- 从环境变量中读取
- 从远程配置系统(etcd或Consor)读取数据,并观察变化
- 从命令行标志读取
- 从缓冲区读取
- 设置显式值
Github地址 :https://github.com/spf13/viper
基本用法
- 本文以读取toml格式的配置文件为例子
- 配置文件定义如下(config.toml)
[app]
port = 9000
init_models = false
loglevel = "debug"
logfile = "/tmp/app/log.log"
static_dir = "/tmp/app/static"
gateway = "localhost"
[secret]
jwt = "a-example-jwt-key"
package main
import (
"fmt"
"github.com/spf13/viper"
"io/ioutil"
"log"
"os"
"reflect"
"strings"
)
type Configure struct {
App struct {
InitModels bool `json:"init_models" remark:"是否初始化数据库模型" must:"false"`
Port int64 `json:"port" remark:"http端口"`
Loglevel string `json:"loglevel" remark:"日志级别"`
Logfile string `json:"logfile" remark:"日志文件"`
StaticDir string `json:"static_dir" remark:"静态文件目录"`
Gateway string `json:"gateway" remark:"网关服务器" must:"false"`
}
Secret struct {
JWT string `json:"jwt" remark:"jwt密钥"`
}
}
func initViper() {
viper.SetConfigName("config")
viper.AddConfigPath(".")
viper.AutomaticEnv()
if len(os.Args) >= 3 {
if os.Args[1] == "-c" {
cfgFile := os.Args[2]
viper.SetConfigFile(cfgFile)
}
}
err := viper.ReadInConfig()
if err != nil {
log.Fatal(err)
}
file := viper.GetViper().ConfigFileUsed()
configData, err := ioutil.ReadFile(file)
if err != nil {
log.Fatal(err)
}
configText := strings.ReplaceAll(string(configData), "&", "|||")
r := strings.NewReader(configText)
err = viper.ReadConfig(r)
if err != nil {
log.Fatalf("初始化配置文件失败:%v", err)
}
}
var Conf = &Configure{}
func main() {
initViper()
confValue := reflect.ValueOf(Conf).Elem()
confType := reflect.TypeOf(*Conf)
for i := 0; i < confType.NumField(); i++ {
section := confType.Field(i)
sectionValue := confValue.Field(i)
for j := 0; j < section.Type.NumField(); j++ {
key := section.Type.Field(j)
keyValue := sectionValue.Field(j)
sec := strings.ToLower(section.Name)
remark := key.Tag.Get("remark")
must := key.Tag.Get("must")
tag := key.Tag.Get("json")
if tag == "" {
err := fmt.Errorf("can not found a tag name `json` in struct of [%s].%s", sec, tag)
log.Fatal(err)
os.Exit(-1)
}
log.Printf("绑定环境变量 ENV_%s_%s ==> %s.%s", strings.ToUpper(sec), strings.ToUpper(tag), sec, tag)
envKey := fmt.Sprintf("ENV_%s_%s", strings.ToUpper(sec), strings.ToUpper(tag))
_ = viper.BindEnv(sec+"."+tag, envKey)
fmt.Printf("获取的环境变量为:%v\n",os.Getenv(envKey))
switch key.Type.Kind() {
case reflect.String:
value := viper.GetString(sec + "." + tag)
if value == "" && must != "false" {
err := fmt.Errorf("get a blank value of must item [%s].%s %s", sec, tag, remark)
log.Fatal(err)
os.Exit(-1)
}
keyValue.SetString(value)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
value := viper.GetInt64(sec + "." + tag)
if value == 0 && must != "false" {
err := fmt.Errorf("get a zero value of must item [%s].%s %s", sec, tag, remark)
log.Fatal(err)
os.Exit(-1)
}
keyValue.SetInt(value)
case reflect.Bool:
value := viper.GetBool(sec + "." + tag)
keyValue.SetBool(value)
case reflect.Slice:
value := viper.GetStringSlice(sec + "." + tag)
val := reflect.ValueOf(&value)
keyValue.Set(val.Elem())
default:
log.Fatalf("unsupported config struct key type %T", key.Type.Kind())
}
}
}
log.Printf("The Result:%v\n",Conf)
}
|