go有 viper 与 configor 配置管理方案。
viper管理配置
https://github.com/spf13/viper
- 支持多种配置文件格式,包括 JSON,TOML,YAML,HECL,envfile,甚至还包括Java properties
- 支持为配置项设置默认值
- 可以通过命令行参数覆盖指定的配置项
- 支持参数别名
viper 按照优先级从高到低获取配置项的取值:
- explicit call to Set: 在代码逻辑中通过viper.Set()直接设置配置项的值
- flag:命令行参数
- env:环境变量
- config:配置文件
- key/value store:etcd或者consul
- default:默认值
package main
import (
"fmt"
"time"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
)
func main() {
loadConfig()
}
func loadConfig() {
configVar := "shuang-config.yaml"
configVar = "" // 这行如果注释掉,则从指定的configVar读取配置文件;否则就各种条件去找了
if configVar != "" {
// SetConfigFile 显式定义配置文件的路径、名称和扩展名。
// Viper 将使用它而不检查任何配置路径。
viper.SetConfigFile(configVar)
} else {
// 如果没有显式指定配置文件,则
// 会去下面的路径里找文件名`cui-config`的文件 name of config file (without extension)
// 按照 []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}的顺序(居然还支持Java用的properties)
viper.SetConfigName("cui-config")
viper.AddConfigPath("/etc/myapp") // 找寻的路径
viper.AddConfigPath("$HOME/.myapp/")
viper.AddConfigPath(".")
}
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Printf("配置文件 %s 发生了更改!!! 最新的Global.Source这个字段的值为 %s:", e.Name, viper.GetString("Global.Source"))
})
err := viper.ReadInConfig()
if err != nil {
panic(fmt.Errorf("error reading config: %s", err))
}
fmt.Printf("到底用的是哪个配置文件: '%s'\n", viper.ConfigFileUsed())
fmt.Printf("Global.Source这个字段的值为: '%s'\n", viper.GetString("Global.Source"))
time.Sleep(10000e9)
}
Watch机制(配置更新后热加载)
该机制可以监听配置文件的修改, 这样就实现了热加载,修改配置后,无需重启服务。
- 对于本地文件,是通过fsnotify实现的,然后通过一个回调函数去通知应用来reload
- 对于Remote KV Store,目前只支持etcd,做法比较ugly,(5秒钟)轮询一次 而不是watch api
configor 管理配置
Configor 支持YAML,JSON,TOML,Shell环境,支持热加载。
出自jinzhu :https://github.com/jinzhu
package main
import (
"fmt"
"time"
"github.com/jinzhu/configor"
)
type Config struct {
APPName string `default:"app name"`
DB struct {
Name string
User string `default:"root"`
Password string `required:"true" env:"DBPassword"`
Port uint `default:"3306"`
}
Contacts []struct {
Name string
Email string `required:"true"`
}
}
func main() {
var conf = Config{}
// reload模式,可实现热加载
err := configor.New(&configor.Config{
AutoReload: true,
AutoReloadInterval: time.Second,
AutoReloadCallback: func(config interface{}) {
// config发生变化后出发什么操作
fmt.Printf("配置文件发生了变更%#v\n", config)
},
}).Load(&conf, "config.yml")
// 无reload模式
//err := configor.Load(&conf, "config.yml")
// err := configor.New(&configor.Config{Debug: true}).Load(&conf, "config.yml") // 测试模式,也可以通过环境变量开启测试模式(CONFIGOR_DEBUG_MODE=true go run main.go ),这样就无需修改代码
//err := configor.New(&configor.Config{Verbose: true}).Load(&conf, "config.yml") // 模式,也可以通过环境变量开启详细模式(CONFIGOR_VERBOSE_MODE=true go run main.go ),这样就无需修改代码
if err != nil {
panic(err)
}
fmt.Printf("%v \n", conf)
time.Sleep(100000e9)
}