Go项目配置文件最佳实践?

1,288 阅读1分钟

基于viper实现Go项目的配置

支持

  • 读取配置文件
  • 设置配置项
  • 读取配置项
  • 动态的读取配置文件
  • 支持自定义修改读取文件的路径

下面是项目的目录结构

截屏2022-03-06 下午9.18.25.png

package conf


import (
   "github.com/spf13/cast"
   viperlib "github.com/spf13/viper" // 自定义包名,避免与内置 viper 实例冲突
   "os"
)
// viper 库实例
var viper *viperlib.Viper

// ConfigFunc 动态加载配置信息
type ConfigFunc func() map[string]interface{}

// ConfigFuncs 先加载到此数组,loadConfig 再动态生成配置信息
var ConfigFuncs map[string]ConfigFunc

func init() {

   // 1. 初始化 Viper 库
   viper = viperlib.New()
   // 2. 配置类型,支持 "json", "toml", "yaml", "yml", "properties",
   //             "props", "prop", "env", "dotenv"
   viper.SetConfigType("env")
   viper.AddConfigPath(".")
   viper.SetEnvPrefix("appenv")
   viper.AutomaticEnv()
   ConfigFuncs = make(map[string]ConfigFunc)
}

func InitConfig(env string) {
   // 1. 加载环境变量
   loadEnv(env)
   // 2. 注册配置信息
   loadConfig()
}

func loadConfig() {
   for name, fn := range ConfigFuncs {
      viper.Set(name, fn())
   }
}

func loadEnv(envSuffix string) {
   envPath := ".env"
   if len(envSuffix) > 0 {
      filepath := ".env." + envSuffix
      if _, err := os.Stat(filepath); err == nil {
         // 如 .env.testing 或 .env.stage
         envPath = filepath
      }
   }

   // 加载 env
   viper.SetConfigName(envPath)
   if err := viper.ReadInConfig(); err != nil {
      panic(err)
   }
   // 监控 .env 文件,变更时重新加载
   viper.WatchConfig()
}

func Env(envName string, defaultValue ...interface{}) interface{} {
   if len(defaultValue) > 0 {
      return internalGet(envName, defaultValue[0])
   }
   return internalGet(envName)
}

func internalGet(path string, defaultValue ...interface{}) interface{} {
   // config 或者环境变量不存在的情况
   if !viper.IsSet(path)  {
      if len(defaultValue) > 0 {
         return defaultValue[0]
      }
      return nil
   }
   return viper.Get(path)
}

// Add 新增配置项
func Add(name string, configFn ConfigFunc) {
   ConfigFuncs[name] = configFn
}

func Get(path string, defaultValue ...interface{}) string {
   return GetString(path, defaultValue...)
}


// GetString 获取 String 类型的配置信息
func GetString(path string, defaultValue ...interface{}) string {
   return cast.ToString(internalGet(path, defaultValue...))
}
package main

import (
   "demo/conf"
   "flag"
   "fmt"
)

func init() {
   conf.Add("app",func() map[string]interface{} {
      return map[string]interface{}{
         "test": conf.Env("TEXT", "Hello Golang!!!"),
      }
})
}
func main() {
   var env string
   flag.StringVar(&env, "env", "","自己配置 如--env=testing ")
   flag.Parse()
   conf.InitConfig(env)
   res := conf.Get("app.test")
   fmt.Println(res)
   fmt.Println(res)
   fmt.Println(res)
   fmt.Println(res)
   fmt.Println(res)
}

项目使用

conf.Add()   //设置配置
conf.Get()   //读取配置
.env    
.env.test   //配置文件
go run main.go --env=test //读取.env.test,默认读取.env