Viper:强大的Go配置解析库

news/2024/11/14 22:25:50/文章来源:https://www.cnblogs.com/wzh2010/p/18364344

1 介绍

Viper是适用于Go应用程序的完整配置解决方案。它被设计用于在应用程序中工作,并且可以处理所有类型的配置需求和格式。目前Star 26.6k, 它支持以下特性:

  • 设置默认值
  • 从JSON、TOML、YAML、HCL、envfile和Java properties格式的配置文件读取配置信息
  • 实时监控和重新读取配置文件(可选)
  • 从环境变量中读取
  • 从远程配置系统(etcd或Consul)读取并监控配置变化
  • 从命令行参数读取配置
  • 从buffer读取配置
  • 显式配置值

2 Golang项目中的使用

2.1 在go中安装Viper

# 终端中输入如下命令
ArchitePlus@MacBook-Air traffic.demo % go get github.com/spf13/viper

2.2 编写通用配置文件

因为能支持多重配置文件格式,包含 JSON、TOML、YAML、HCL、INI、envfile 和 Java 属性文件,方便开发者根据项目需求选择合适的格式。
我们这边使用yaml做示例。

创建一个conf文件夹,添加子文件夹files,然后在下面添加config.yaml,里面可以放一些基本的、通用的配置信息。

app: # 应用基本配置env: local # 环境名称port: 8888 # 服务监听端口号app_name: traffic-demo # 应用名称app_url: http://localhost # 应用访问地址MySQL: # MySQL配置host: 127.0.0.1 # MySQL主机地址port: 3306 # MySQL端口号user: root # MySQL用户名password: <PASSWORD> db_name: traffic # MySQL数据库名

可以看到,我们有两个配置信息,一个是 app,一个是MySQL。

2.3 编写用户自定义配置文件

还有一些用户自定义的配置文件(可能有多个), 是需要根据不同的运行环境(local、dev、beta、prod)来进行区分的.所以我们在config/files/下面创建四个文件夹 localdevbetaprod 四个文件夹,每个文件夹都有一个custom.yaml文件,当 app.env 的值变化的时候,读取的文件也跟着变化,下面是local的信息

white_list: user_id: # 用户列表- 063105015- 063105024- 063105028request_path: # 访问路径- /api/v1/users- /api/v1/ops

2.4 配置映射的结构体

我们需要配置结构体(实体对象)来映射这俩配置,这样的话,后面在调用的时候非常方便。
conf文件夹下面添加子文件夹model,存放解析映射的结构体,这边新增一个config.go和一个custom.go文件,内容如下:

2.4.1 config.go

package config// 配置文件解析汇总
type Configuration struct {App   App   `mapstructure:"app" json:"app" yaml:"app"`MYSQL MYSQL `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
}// 配置文件解析:app
type App struct {Env     string `mapstructure:"env" json:"env" yaml:"env"`Port    string `mapstructure:"port" json:"port" yaml:"port"`AppName string `mapstructure:"app_name" json:"app_name" yaml:"app_name"`AppUrl  string `mapstructure:"app_url" json:"app_url" yaml:"app_url"`
}// 配置文件解析:mysql
type MYSQL struct {Host     string `mapstructure:"host" json:"host" yaml:"host"`Port     string `mapstructure:"poet" json:"port" yaml:"port"`User     string `mapstructure:"user" json:"user" yaml:"user"`Password string `mapstructure:"password" json:"password" yaml:"password"`DbName   string `mapstructure:"db_name" json:"db_name" yaml:"db_name"`
}

2.4.2 custom.go

package configtype Custom struct {WhiteList whiteList `mapstructure:"white_list" json:"white_list" yaml:"white_list"`
}// 配置文件解析汇总
type whiteList struct {UserId      []string `mapstructure:"user_id" json:"user_id" yaml:"user_id"`RequestPath []string `mapstructure:"request_path" json:"request_path" yaml:"request_path"`
}

2.5 创建Global全局变量解析

新建一个 global/app.go 文件,定义 Application 结构体,用来存放一些项目启动时的变量,方便调用。
目前先将 viper 结构体和 Configuration 结构体放入,后续会陆续添加其他配置信息。

package globalimport ("github.com/spf13/viper"config "traffic.demo/config/model"
)// 定义一个全局的Application
type Application struct {ConfigViper *viper.ViperConfig      config.ConfigurationCustom      config.Custom
}// 初始化Application
var App = new(Application)

2.5 关键步骤:结构体映射逻辑

配置文件要映射到结构体,这样才能把配置数据提取出来,这边创建 bootstrap/config.go 文件,作为核心解析代码的载体,代码如下(代码中的解释已经很清楚了):

package bootstrapimport ("fmt""github.com/fsnotify/fsnotify""github.com/spf13/viper""traffic.demo/global"
)// configAssemble 是一个泛型函数,用于组装配置文件并返回 viper.Viper 指针
//
// 参数:
//
//	configPath string - 配置文件路径
//	viperStruct T - 用来接收配置文件的结构体
//
// 返回值:
//
//	*viper.Viper - viper.Viper 指针
func configAssemble[T any](configPath string, viperStruct T) *viper.Viper {// 初始化 viperv := viper.New()// 配置文件地址v.SetConfigFile(configPath)// 配置文件类型,yamlv.SetConfigType("yaml")if err := v.ReadInConfig(); err != nil {panic(fmt.Errorf("read config failed: %s \n", err))}// 监听配置文件v.WatchConfig()v.OnConfigChange(func(in fsnotify.Event) {fmt.Println("config file changed:", in.Name)// 重载配置 &global.App.Configif err := v.Unmarshal(viperStruct); err != nil {fmt.Println(err)}})// 将配置赋值给全局变量 &global.App.Configif err := v.Unmarshal(viperStruct); err != nil {fmt.Println(err)}return v
}// InitializeConfig 初始化配置函数
func InitializeConfig() {// 全局应用文件配置路径,这边是我们的具体global config文件地址config := "conf/files/config.yaml"configAssemble(config, &global.App.Config)// 用户自定义的配置(根据不同的运行环境,加载不同的配置文件)customConfig := fmt.Sprintf("%s%s%s", "conf/files/", global.App.Config.App.Env, "/custom.yaml")configAssemble(customConfig, &global.App.Custom)}

2.6 整体文件结构如下

image

2.7 运行结果

main.go 代码如下:

package mainimport ("fmt""traffic.demo/global"
)// main 函数是程序的入口点
func main() {bootstrap.InitializeConfig()fmt.Println("Traffic Service Started...!")var globalCong = global.App.Configfmt.Printf("globalCong: %+v\n", globalCong)var customCong = global.App.Customfmt.Printf("customCong: %+v\n", customCong)
}

效果如下:
image

3 总结

Viper 是一个功能强大、简洁、易于的 Go 配置库,帮助开发者轻松管理应用程序的配置,并提供灵活的接入方式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/784102.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JetBrains GoLand 2024.2 (macOS, Linux, Windows) - 为 Go 开发者打造的完整 IDE

JetBrains GoLand 2024.2 (macOS, Linux, Windows) - 为 Go 开发者打造的完整 IDEJetBrains GoLand 2024.2 (macOS, Linux, Windows) - 为 Go 开发者打造的完整 IDE JetBrains 跨平台开发者工具 请访问原文链接:https://sysin.org/blog/jetbrains-goland/,查看最新版。原创作…

流媒体服务器如何让WebRTC支持H.265,同时又能支持Web Chrome硬解码、软解码:DataChannel+MSE+WASM解码H.265

为了这一整套的解决方案,调研+研发整整花费了差不多半年多的时间,需达成的目标:流媒体服务器端不需要将H.265转码成H.264,就能让Chrome解码播放H.265;注意:现在很多市面上的软硬件通过转码H.265成H.264的方式来支持WebRTC,个人理解,这既费硬件又是技术的倒退!Web JS解…

Avalonia 后台代码简单播放动画示例

本文将演示如何在 Avalonia 的后台代码里面创建 Animation 执行播放本文演示的内容是将界面里面的一个 TextBlock 控件,通过修改控件的 RenderTransform 的 TranslateTransform 执行平移 为了方便演示,先在 MainView.axaml 里面添加一个 TextBlock 控件,如下面代码。大家可以…

读软件开发安全之道:概念、设计与实施03威胁

读软件开发安全之道:概念、设计与实施03威胁1. 威胁 1.1. 威胁常常比事件本身更加可怖1.1.1. 索尔阿林斯基1.2. 威胁无处不在1.2.1. 如果妥善管理,我们也可以安然与威胁共存1.2.2. 我们自己没有几百万年进化而来的本能来防御软件方面的威胁1.3. 把视角从软件构建者转向攻击者…

ubuntu18.04安装dns服务器

1. 安装dnsmasqsudo apt install dnsmasq 2. 在配置文件/etc/dnsmasq.conf末尾添加自定义域名 3. 测试配置文件sudo dnsmasq --test 4. 开启dns服务sudo systemctl restart dnsmasq

CloudFlare Workers 日志管理方案全解析

CloudFlare Workers, Logpush, Tail Workers, Real-time Logging, 实时日志服务, 低成本目录引言 Logpush介绍 推送目标 操作步骤Tail Workers介绍 操作步骤实时日志介绍 使用方法 局限性替代方案:手动发送日志实现方式 注意事项方案选择推荐方案:手动发送日志到Sentry总结在…

java八股 并发+数据结构

CAS缺点耗费cpu aba问题当前进度 https://javaguide.cn/java/concurrent/java-concurrent-questions-02.html#reentrantreadwritelock

035、Vue3+TypeScript基础,路由params参数时,使用defineProps自动获得数据

01、New.vue代码如下:<template><div class="app-container"><!-- 导航区域容器 --><div class="sidebar"><ul class="news-list"><!--第一种写法--><li v-for="news in newsList" :key=&quo…

Vue3---基础

vue3基础: vue2里面做一个基础的数据渲染:在VUE3里面,可以直接声明在 setup 函数里面: 此时会发现仅仅是单向数据绑定,使用ref进行双向数据绑定:还可以进行简化:同样可以写一个点击事件:打完收工!

【待看】EDR联动数据包封锁技术

一、摘要 利用中间人攻击(PitM)和过滤EDR特定通讯数据包, 可以干扰和阻止EDR与云服务器的通讯过程, 从而有效隐藏报警信息, 使其不被SOC团队察觉。这种效果可以通过对目标主机实行ARP欺骗并配置iptables来实现。这种方法的优势在于不需要管理员权限或对受害主机的访问, 但需要一…

034、Vue3+TypeScript基础,路由params参数的使用

01、main.js代码如下:// 引入createApp用于创建Vue实例 import {createApp} from vue // 引入App.vue根组件 import App from ./App.vue//引入路由 import router from ./routerconst app = createApp(App); //使用路由 app.use(router); // App.vue的根元素id为app app.mount…

RocketMQ 的convertAndSend方法和syncSend方法区别

RocketMQ的convertAndSend方法和syncSend方法是两种不同的消息发送 convertAndSend方法是将消息内容转换为指定的格式,然后发送到指定的消息队列。这个方法是异步发送的,也就是说,发送消息后就立即返回并不等待对方的响应。 syncSend方法则是同步发送消息,也就是说发送消息…