Go中的应用配置管理详解
本篇文章向大家介绍《Go中的应用配置管理详解》,主要包括应用配置、配置管理,具有一定的参考价值,需要的朋友可以参考一下。
问题
- Go语言在编译时不会将配置文件这类第三方文件打包进二进制文件中
- 它既受当前路径的影响,也会因所填写的不同而改变,并非是绝对可靠的
解决
命令行参数
在Go语言中,可以直接通过flag标准库来实现该功能。实现逻辑为,如果存在命令行参数,则优先使用命令行参数,否则使用配置文件中的配置参数。
如下:
var (
port string
runMode string
config string
)
func init() {
// 获取命令行参数
err = setupFlag()
if err != nil {
log.Fatalf("init.setupFlag err: %v", err)
}
......
}
// 获取命令行参数
func setupFlag() error {
flag.StringVar(&port, "port", "", "启动端口")
flag.StringVar(&runMode, "mode", "", "启动模式")
flag.StringVar(&config, "config", "config/", "指定要使用的配置文件路径")
flag.Parse()
return nil
}
通过上述代码,我们可以通过标准库flag读取命令行参数,然后根据其默认值判断配置文件是否存在。若存在,则对读取配置的路径进行变更,代码如下:
package setting
import "github.com/spf13/viper"
type Setting struct {
vp *viper.Viper
}
// 初始化配置文件的基础属性
func NewSetting(configs ...string) (*Setting, error) {
vp := viper.New()
vp.SetConfigName("config")
if len(configs) != 0 {
for _, config := range configs {
if config != "" {
vp.AddConfigPath(config)
}
}
} else {
vp.AddConfigPath("configs/")
}
vp.SetConfigType("yaml")
err := vp.ReadInConfig()
if err != nil {
return nil, err
}
return &Setting{vp}, nil
}
接下来,对ServerSetting配置项进行覆写。如果存在,则覆盖原有的文件配置,使其优先级更高,代码如下:
// 初始化配置文件
func setupSetting() error {
setting, err := setting2.NewSetting(strings.Split(config, ",")...)
if err != nil {
return err
}
......
if port != "" {
global.ServerSetting.HttpPort = port
}
if runMode != "" {
global.ServerSetting.RunMode = runMode
}
return nil
}
然后在运行的时候传入参数即可:
go run main.go -port=8081 -mode=debug -config=configs/
系统环境变量
可以将配置文件存放在系统自带的全局变量中,如$HOME/conf或/etc/conf中,这样做的好处是不需要重新自定义一个新的系统环境变量。
一般来说,我们会在程序中内置一些系统环境变量的读取,其优先级低于命令行参数,但高于文件配置。
打包进二进制文件
可以将配置文件这种第三方文件打包进二进制文件中,这样就不需要过度关注这些第三方文件了。但这样做是有一定代价的,因此要注意使用的应用场景,即并非所有的项目都能这样操作。
首先安装go-bindata库,安装命令如下:
go get -u github.com/go-bindata/go-bindata/...
通过go-bindata库可以将数据文件转换为Go代码。例如,常见的配置文件、资源文件(如Swagger UI)等都可以打包进Go代码中,这样就可以“摆脱”静态资源文件了。接下来在项目根目录下执行生成命令:
go-bindata -o configs/config.go -pkg-configs configs/config.yaml
执行这条命令后,会将 configs/config.yaml 文件打包,并通过-o 选项指定的路径输出到configs/config.go文件中,再通过设置的-pkg选项指定生成的packagename为configs,接下来只需执行下述代码,就可以读取对应的文件内容了:
b,_:=configs.Asset("configs/config.yaml")
把第三方文件打包进二进制文件后,二进制文件必然增大,而且在常规方法下无法做文件的热更新和监听,必须要重启并且重新打包才能使用最新的内容,因此这种方式是有利有弊的。
配置热更新
开源的fsnotify
既然要做配置热更新,那么首先要知道配置是什么时候修改的,做了哪些事?因此我们需要对所配置的文件进行监听,只有监听到了,才能知道它做了哪些变更。
开源库 fsnotify 是用Go语言编写的跨平台文件系统监听事件库,常用于文件监听,因此我们可以借助该库来实现这个功能。
(1)安装
go get -u golang.org/x/sys/... go get -u github.com/fsnotify/fsnotify
fsnotify是基于golang.org/x/sys实现的,并非syscall标准库,因此在安装的同时需要更新其版本,确保版本是最新的。
(2)案例
package main
import (
"gopkg.in/fsnotify.v1"
"log"
)
func main() {
watcher, _ := fsnotify.NewWatcher()
defer watcher.Close()
done := make(chan bool)
go func() {
for {
select {
case event, ok :=
通过监听,我们可以很便捷地知道文件做了哪些变更。进一步来说,我们可以通过对其进行二次封装,在它的上层实现一些变更动作来完成配置文件的热更新。
使用viper开源库实现热更新
viper开源库能够很便捷地实现对文件的监听和热更新。
打开pkg/setting/section.go文件,针对重载应用配置项,新增如下处理方法:
var sections = make(map[string]interface{})
// 解析配置文件
func (s *Setting) ReadSection(k string, v interface{}) error {
err := s.vp.UnmarshalKey(k, v)
if err != nil {
return err
}
if _,ok:=sections[k];!ok{
sections[k] = v
}
return nil
}
首先修改ReadSection方法,增加读取section的存储记录,以便在重新加载配置的方法中进行二次处理。接下来新增ReloadAllSection方法,重新读取配置,代码如下:
// 读取所有配置
func (s *Setting) ReadAllSections() error {
for k, v := range sections {
err := s.ReadSection(k, v)
if err != nil {
return err
}
}
return nil
}
// 监听配置变化
func (s *Setting) WatchSettingChange() {
go func() {
s.vp.WatchConfig()
s.vp.OnConfigChange(func(in fsnotify.Event) {
_ = s.ReloadAllSections()
})
}()
}
最后在pkg/setting/setting.go文件中新增文件热更新的监听和变更处理,代码如下:
// 初始化配置文件的基础属性
func NewSetting(configs ...string) (*Setting, error) {
vp := viper.New()
vp.SetConfigName("config")
for _, config := range configs {
if config != "" {
vp.AddConfigPath(config)
}
}
vp.SetConfigType("yaml")
err := vp.ReadInConfig()
if err != nil {
return nil, err
}
// 加入热更新
s := &Setting{vp: vp}
s.WatchSettingChange()
return s, nil
}
在上述代码中,首先在NewSetting方法中起一个协程,再在里面通过WatchConfig方法对文件配置进行监听,并在OnConfigChange方法中调用刚刚编写的重载方法ReloadAllSection来处理热更新的文件监听事件回调,这样就可以“悄无声息”地实现一个文件配置热更新了。
OnConfigChange方法的回调方法形参,其实就是fsnotify。
今天带大家了解了应用配置、配置管理的相关知识,希望对你有所帮助;关于Golang的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~
Go语言包和包管理详解
- 上一篇
- Go语言包和包管理详解
- 下一篇
- Go保证并发安全底层实现详解
-
- Golang · Go教程 | 1天前 | map · 并发安全 · RWMutex · sync.Map · Go教程 · 并发安全 RWMutex sync.Map Go map并发读写 go test race
- Go map 并发读写崩溃怎么办:从复现报错到 RWMutex 修复的完整流程
- 272浏览 收藏
-
- Golang · Go教程 | 3天前 | singleflight · 并发控制 · Go教程 · 缓存治理 · 接口优化 · Go 并发请求 缓存击穿 singleflight 缓存回填
- Go singleflight 防缓存击穿实战:相同请求只查一次数据库
- 114浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ljg-skills
- ljg-skills 是李继刚开源的 AI 技能与提示词集合,面向大模型使用者整理了一批可复用的 prompt、角色设定和任务技能模板,适合用于学习提示词设计、搭建个人 AI 工作流和沉淀团队常用智能体能力。
- 185次使用
-
- MELO音乐
- MELO音乐是一站式AI视频与音乐制作助手,对标suno, udio的高品质体验。提供伴奏生成、原创写词、无损导出、哼唱识曲、混音变声等全套音频与短视频编辑工具。无论是流行Kpop、电音说唱、民谣古风、摇滚儿歌还是商用轻音乐,MELO为你免费谱曲,轻松做同款!
- 204次使用
-
- UniScribe
- UniScribe 是一款 AI 音视频转文字与内容整理工具,支持上传音频、视频文件或粘贴 YouTube 链接,自动生成转写文本、摘要、思维导图和关键问题,并支持多格式导出,适合会议记录、课程学习、访谈整理和内容创作复盘。
- 180次使用
-
- 剧云
- 剧云是专业中文剧本创作平台,安全稳定运行十余年,集成AI编剧、剧本医生审核、人物小传、剧情关系图、大纲编写、多人协作、Word导入导出、版权管控功能,数据安全防护,轻松高效创作剧本。
- 344次使用
-
- 万象有声
- 万象有声,一个专为有声创作者打造的新一代智能有声内容创作平台。平台提供专业的智能拆章、智能画本编辑、AI配音、AI生成音效、后期制作、智能对轨、智能审听等有声创作全流程工具,可以帮助创作者高效、低成本创作出引人入胜的有声作品。立即体验,让有声书制作更简单!
- 342次使用
-
- golang配置管理神器Viper使用教程
- 2022-12-27 266浏览
-
- Go项目配置管理神器之viper的介绍与使用详解
- 2023-02-25 303浏览
-
- springboot集成Nacos 实现多环境动态配置
- 2023-01-10 256浏览
-
- Python Flask 实战:别把请求上下文当全局变量用
- 2026-06-04 257浏览
-
- Python dataclass 配置管理实战:默认值、环境变量覆盖和启动校验
- 2026-06-13 131浏览

