Go 项目配置的定制化和一体化打包方案

server/2024/10/22 0:48:51/

config在项目中的实现形式多种多样,小成本项目把项目存放在项目自身单独的文件中,文件格式既可以是程序文件,也可以是JSON、YAML这样的静态文件。具有相当大访问量又需要配置能热更新的项目则会使用远程配置中心。

本节我们来实现项目的配置的功能。这里我们需要用到一个Go语言写的开源库使用Viper,选用Viper主要原因是支持它支持从项目文件、远端ETCD和Consul中读取配置,兼容性更高一些。

本文主要内容如下:

67f18bc255b082dd0c4dbf0d6bdf432b.png

本节代码版本为c2, 大家加入项目后可直接访问https://github.com/go-study-lab/go-mall/compare/c1...c2 对比与上次版本的代码变更更容易自己进行学习和动手实战。
0c6d1b508dea91f078d1a800f610d7ab.png

项目加入方式:查看文章末尾海报或者复制链接在浏览器中打开:https://xiaobot.net/p/golang  。

配置的规划

首先提到配置我首先想到的是应该怎么规划和设计

  • 支持项目不同运行环境的配置切换

  • 配置文件使用JSON还是YAML格式

  • 配置应不应该保持只读

第一个问题很好理解,假如项目只有一个配置文件,程序不能按照环境自动加载相应的配置,那可就太麻烦了每次启动前还得先检查配置有没有切过来,而且还有误操作的风险,比如在开发环境直接连生产环境的数据库,不能连上还好说,要是开发环境能连上生产库那问题就更大了。

配置文件的格式,其实用JSON还是YAML都可以,只不过YAML的风格在配置项较多的时候会显得更清晰一些,这个其实没用特别要求必须用哪个,大家搭建项目时尽量选择支持读取多种文件格式配置的开源库,比如这里会用到的Viper。

配置加载到程序后尽量不要去进行更改,因为这些配置大部分都是全局的一旦更改很有可能会影响项目其他部分的程序。这个从程序的语法层面上限制比较困难,所以需要我们在团队内部先达成配置只能是只读的这种共识。

综合以上分析我们对项目的配置作出如下规划:

在项目目录下新建config目录,里面放置我们的应用日志,目录中的文件如下

.
|-- config
|   `-- application.dev.yaml
|   `-- application.prod.yaml
|   `-- application.test.yaml
|   `-- bootstrap.go
|   `-- config.go
|-- main.go
|-- go.mod
|-- go.sum

application.dev.yaml 定义的是应用的配置,通过文件后缀就猜到,在开发环境运行应用时会加读取此文件中的配置

app:env: devname: go-mall
database:type: mysqldsn: "reserved"maxopen: 100maxidle: 10maxlifetime: 300

与此同时我们还会有application.test.yaml 和 application.prod.yaml 文件用来分别设置应用在测试和生产运行环境中的配置。

另外两个boostrap.go 和 config.go 是下面使用Viper读取加载配置时用到的。

使用 Viper 加载和读取配置

项目安装 Viper 依赖

go get github.com/spf13/viper@v1.12.0

为了兼容性,选择一个稍旧的版本,viper@v1.12.0 后面的版本会不支持Yaml 2 的语法

Viper 加载配置

bootstrap.go 是加载配置文件,把配置解析到配置对象中。

c44f060708d68c9e04173554f0b4c441.png

config.go中则是定义了我们会使用到的配置对象

var (App      *appConfigDatabase *databaseConfig
)type appConfig struct {Name string `mapstructure:"name"`Env  string `mapstructure:"env"`
}type databaseConfig struct {Type        string        `mapstructure:"type"`DSN         string        `mapstructure:"dsn"`MaxOpenConn int           `mapstructure:"maxopen""`MaxIdleConn int           `mapstructure:"maxidle"`MaxLifeTime time.Duration `mapstructure:"maxlifetime"`
}

做好后,先写个方法快速测试一下对不对

g.GET("/config-read", func(c *gin.Context) {database := config.Databasec.JSON(http.StatusOK, gin.H{"type":     database.Type,"max_life": database.MaxLifeTime,})})

运行后,报错。。。

panic: Config file not found, file path: config/application.yaml

因为找不到配置文件 “config/application.yaml”, 原因是我们没有设置这个环境变量,我们先在电脑的环境变量里先配置上ENV这个环境变量。

同理程序部署的服务器也要根据所在的运行环境设置ENV这个环境变量,这样程序发布到不同的运行环境才能自动采用对应环境的配置。

到这里你是不是以为配置的大体架子就好了?其实没有,在IDE里直接运行项目是用go run 运行的。 而真正运行程序的时候是先使用 go build 编译打包然后在执行打包后的程序。

Go项目编译后配置文件丢了?

这里就涉及到一个知识点,Go编译时默认只会把go 文件打包进二进制包中,YAML这样的静态文件不会被打包进去,这样编译之后只把二进制包部署到服务上Go程序是没办法读到配置文件的。

我们可以自己做个测验编译打包成执行文件后,把它放到其他目录下执行试试

go build ./ 
mv go-mall ~/Desktopcd ~/Desktop && go-mall
panic: Config file not found, file path: config/application.dev.yaml
......
Process finished with the exit code 2

别看报错看似是我们程序里设置的配置文件是相对路径,其实即使程序里写的是绝对路径,当我们把文件部署到其他服务器上后运行时,也是会报这个错的。

关于这个问题怎么解决,怎么让Go程序真的变成“一次编译到处运行”,以及如何让Viper使用Etcd作为远程配置中心,欢迎订阅专栏,加入我们的项目,项目中会通过Github Issue来记录和解答项目开发过程中大家提的各种问题,也有专属的读者群,欢迎加入一起学习

7c3a1158803ec1f18e4e7b986f1afa30.png

专栏分为五大部分:

b636ff18dc532dad9ea85f77bbd532fa.png

  • 第一部分介绍让框架变得好用的诸多实战技巧,比如通过自定义日志门面让项目日志更简单易用、支持自动记录请求的追踪信息和程序位置信息、通过自定义Error在实现Go error接口的同时支持给给错误添加错误链,方便追溯错误源头。

  • 第二部分:讲解项目分层架构的设计和划分业务模块的方法和标准,让你以后无论遇到什么项目都能按这套标准自己划分出模块和逻辑分层。后面几个部分均是该部分所讲内容的实践。

  • 第三部分:设计实现一个套支持多平台登录,Token泄露检测、同平台多设备登录互踢功能的用户认证体系,这套用户认证体系既可以在你未来开发产品时直接应用

  • 第四部分:商城app C端接口功能的实现,强化分层架构实现的讲解,这里还会讲解用责任链、策略和模版等设计模式去解决订单结算促销、支付方式支付场景等多种多样的实际问题。

  • 第五部分:单元测试、项目Docker镜像、K8s部署和服务保障相关的一些基础内容和注意事项

具体的章节可扫描上面海报的二维码或者访问 https://xiaobot.net/p/golang

点击下方阅读原文即可跳转。


http://www.ppmy.cn/server/133755.html

相关文章

Qt-界面优化控件样式设置(72)

目录 描述 QPushButton 自定义复选框 输入框 列表框 菜单 实现登入界面 设置背景图 改变样式表 描述 这里介绍一些控件的样式设置 QPushButton 相关属性 font-size设置⽂字⼤⼩.border-radius设置圆⻆矩形. 数值设置的越⼤, ⻆就 "越圆".background-colo…

24.安卓逆向-frida基础-objection工具3-实战

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 内容参考于:图灵Python学院 本人写的内容纯属胡编乱造,全都是合成造假,仅仅只是为了娱乐,请不要盲目相信。 工…

Flume抽取数据(包含自定义拦截器和时间戳拦截器)

flume参考网址:Flume 1.9用户手册中文版 — 可能是目前翻译最完整的版本了https://flume.liyifeng.org/?flagfromDoc#要求: 使用Flume将日志抽取到hdfs上:通过java代码编写一个拦截器,将日志中不是json数据的数据过滤掉&#xf…

微信小程序使用MQTT连接阿里云

目录 一、新建项目和项目整体配置​ 二、MQTT 下载引入和配置连接​ 三、阿里云配置 1、创建产品及设备 2、数据进行云流转 四、创建 MQTT 连接​ 五、微信小程序配置 六、效果展示 1、微信小程序发送控制命令 2、LED台灯反馈LED状态 七、微信小程序项目完整代码 一…

Android10 recent键相关总结

目录 初始化流程 点击Recent键流程 RecentsActivity 显示流程 RecentsModel 获取数据管理类 RecentsActivity 布局 已处于Recent界面时 点击recent 空白区域 点击返回键 recent组件配置 Android10 Recent 功能由 System UI,Launcher共同实现。 初始化流程 …

react+video:限制快进、倍速、画中画

实现代码&#xff1a; <video ref{videoRef} src{videoUrl} className{style.video} controls onRateChange{rateChange} onPlay{playVideo} onPause{pauseVideo} onTimeUpdate{timeUpdate} disablePictureInPicture playsInline poster{poster} controlsList"nodownl…

在 Flutter鸿蒙next版本 中使用 if 语句和三元表达式进行视图逻辑判断

目录 写在前面 1. 使用 if 语句 1.1 使用 if 语句 1.2 使用多个条件 2. 使用三元表达式 2.1 简单示例 2.2 结合多条件判断 写在最后 最佳实践 写在前面 在 Flutter 开发中&#xff0c;构建动态和响应式的用户界面是一个核心任务。在显示视图时&#xff0c;我们经常需要…

网络空间指纹:新型网络犯罪研判的关键路径

前言 新型网络犯罪是指利用计算机技术和互联网平台进行犯罪活动的一类犯罪行为。它涵盖了一系列使用网络和数字技术进行非法活动的行为&#xff0c;如网络钓鱼、网络诈骗、恶意软件攻击、黑客入侵、数据泄露、网络色情和社交网络犯罪等。 随着当前打击治理新型网络犯罪博弈态…