Go项目配置管理工具---Viper

news2024/11/28 15:50:50

目录

  • Viper概述
    • 前言
    • 功能
    • viper配置优先级
  • 从Viper中获取值
    • 读取配置文件
    • 注册和使用别名
  • 把值写入Viper
    • 设置默认值
    • 使用Set方法设置值
    • 把配置信息写入配置文件
    • 从io.Reader中读取配置信息到viper
  • 监控Viper文件

Viper概述

前言

对于现代应用程序,尤其大中型的项目来说,在程序启动和运行时,往往需要传入很多参数来控制程序的行为,这些参数可以通过以下几种方式传递给程序:

  • 命令行参数
  • 环境变量
  • 配置文件

显然,对于Go项目而言,单个去读取命令行、环境变量、配置文件并不难,但一个个读取却是很麻烦,有没有一个第三方库可以帮我们一次性读取上面几种数据源的配置呢?有的,就是使用 viper 库,viper支持读取不同数据源和不同格式的配置文件,是Go项目读取配置的神器。

功能

  • 支持配置key默认值设置
  • 支持读取JSON,TOML,YAML,HCL,envfile和java properties等多种不同类型配置文件
  • 可以监听配置文件的变化,并重新加载配置文件
  • 读取系统环境变量的值
  • 读取存储在远程配置中心的配置数据,如ectd,Consul,firestore等系统,并监听配置的变化
  • 从命令行读取配置
  • 从buffer读取配置
  • 可以显示设置配置的值

viper配置优先级

viper支持从多个数据源读取配置值,因此当同一个配置key在多个数据源有值时,viper读取的优先级如下:

  • 显示使用Set函数设置值
  • flag:命令行参数
  • env:环境变量
  • config:配置文件
  • key/value store:key/value存储系统,如(etcd)
  • default:默认值

优先级示意图

img

从Viper中获取值

读取配置文件

demo环境有两个配置文件config.yaml和config.json,其中config.yaml配置的是mysql,而config.json配置的是gin。demo环境的目录结构如下:

image-20230608154532331

viper支持JSONTOMLYAMLHCLenvfileJava properties格式的配置文件。

第一种方式:直接指定文件路径

viper.SetConfigType("yaml")
viper.SetConfigFile("./connect/config.yaml") // 注意:如果使用相对路径,则是以main.go为当前位置与配置文件之间的路径
err := viper.ReadInConfig() // 查找并读取配置文件
if err != nil {             // 处理读取配置文件的错误
    panic(fmt.Errorf("Fatal error config file: %s \n", err))
}
mysql := viper.Get("mysql")
fmt.Println(mysql)

SetConfigType方法指定了viper读去配置文件的类型,SetConfigFile方法指定配置文件路径。上面的例子中指定读取yaml文件,则json配置文件就不会被读取,反之亦然。

但是,如果没有指定配置文件的类型,指定了两次配置文件的路径(想把.json文件和.yaml文件都读取),那么结果是怎样的呢?其实SetConfigFile方法中的路径有被覆盖的特点,也就是只能指定一个路径。如果指定了多个,谁在下面谁就会生效。所以在下面的例子中,config.json配置文件被读取。

viper.SetConfigFile("./config/config.yaml") //被覆盖了,不会被读取
viper.SetConfigFile("./config/config.json") //配置文件被读取,gin框架,端口:8080

err := viper.ReadInConfig() // 查找并读取配置文件
if err != nil {             // 处理读取配置文件的错误
    panic(fmt.Errorf("Fatal error config file: %s \n", err))
}
mysql := viper.Get("mysql")
gin := viper.Get("gin")
fmt.Println(mysql)
fmt.Println(gin)

运行结果如下:

image-20230608160038865

第二种方式:多路径查找

viper.SetConfigName("config")
viper.AddConfigPath("D:\\GolandProjects\\ViperDemo\\config")

err := viper.ReadInConfig() // 查找并读取配置文件
if err != nil {             // 处理读取配置文件的错误
    panic(fmt.Errorf("Fatal error config file: %s \n", err))
}
mysql := viper.Get("mysql")
gin := viper.Get("gin")
fmt.Println(mysql)
fmt.Println(gin)

SetConfigName方法用来指定配置文件的名称(无扩展名),设置成功后viper只会读取以config开头的配置文件。AddConfigPath方法用来添加配置文件的路径,可以添加多个。但是,如果在同一个路径下有多个相同的配置文件名(扩展名不同),则只会读取第一个配置文件。看看我上面的config目录下的文件顺序,所以只会读取config.json的配置信息,而config.yaml的配置信息会被忽略。运行结果如下:

image-20230608161905140

注册和使用别名

viper.Set("name", "green")
//为name设置一个username的别名
viper.RegisterAlias("username", "name")

//通过username可以读取到name的值
fmt.Println(viper.Get("username")) //green

//修改name的配置值,username的值也发生改变
viper.Set("name", "blue")
fmt.Println(viper.Get("username")) //blue

//修改username的值,name的值也发生改变
viper.Set("username", "red")
fmt.Println(viper.Get("name")) //red

把值写入Viper

设置默认值

一个好的配置系统应该支持默认值。如果没有通过配置文件、环境变量、远程配置或命令行标志等设置键的值,则默认值非常有用。例如:

func Viper() {
	viper.SetDefault("secret_key", "123abc")
	viper.SetDefault("mysql", map[string]interface{}{"host": "127.0.0.1", "port": 3306})
	fmt.Println(viper.Get("secret_key"))
	fmt.Println(viper.Get("MYSQL")) //viper中配置的key值是不区分大小写的
}

运行结果如下:

image-20230608144432814

使用Set方法设置值

这种方式的优先级最高,会覆盖该key用其他方式设置的值。

viper.Set("gin", map[string]interface{}{"port": 8080})
viper.Set("gin", map[string]interface{}{"port": 8888}) //使用set设置值是可以被覆盖的
fmt.Println(viper.Get("gin"))

运行结果如下:

image-20230608145136353

把配置信息写入配置文件

除了读取配置文件外,viper也支持将配置值写入配置文件,viper提供了四个函数,用于将配置写回文件。

  1. WriteConfig:将配置写入预先设置好路径的配置文件中,如果配置信息存在,则覆盖,如果没有,则创建。
viper.SetConfigFile("./config/config.yaml")
err := viper.ReadInConfig()
if err != nil {
    panic(fmt.Errorf("failed to read config file: %s", err))
}
// 设置配置项
viper.Set("mysql.password", "password")
// 写入配置文件
err = viper.WriteConfig()
if err != nil {
    panic(fmt.Errorf("failed to write config file: %s", err))
}
  1. SafeWriterConfig:与WriteConfig函数唯一的不同是如果配置文件存在,则会返回一个错误。
// 设置配置项
viper.Set("mysql.password", "password") //在上面的例子中已经将这个配置写入到了配置文件中
// 写入配置文件
err = viper.SafeWriteConfig()  //返回一个错误
if err != nil {
    panic(fmt.Errorf("failed to write config file: %s", err))
}

运行结果如下:

image-20230608181232262

  1. WriteConfigAs:与WriteConfig函数的不同是需要传入配置文件保存路径,viper会根据文件后缀判断写入格式。
data := map[string]interface{}{
    "database": map[string]interface{}{
        "host":     "localhost",
        "port":     3306,
        "username": "root",
        "password": "password",
        "dbname":   "demo",
    },
    "server": map[string]interface{}{
        "host": "127.0.0.1",
        "port": 8080,
    },
}
viper.SetConfigFile("./config/config.yaml")
err := viper.ReadInConfig()
if err != nil {
    panic(fmt.Errorf("failed to read config file: %s", err))
}

//将后端生成的配置数据设置到 Viper 实例中
for key, value := range data {
    viper.Set(key, value)
}
// 写入配置文件
err = viper.WriteConfigAs("./config/config.toml") //参数是配置文件的路径
if err != nil {
    panic(fmt.Errorf("failed to write config file: %s", err))
}

WriteConfigAs方法后面的参数是配置文件的存放路径,如果没有相应的配置文件,就会新建一个配置文件。如果有就会直接把数据写入文件中。

  1. SafeWriteConfigAs:与WriteConfigAs的唯一不同是如果配置文件存在,则返回一个错误。具体就不在演示了。

从io.Reader中读取配置信息到viper

Viper预先定义了许多配置源,如文件、环境变量、标志和远程K/V存储,但这只是预定义,其实自己也能实现自己所需的配置源并将其提供给viper。

viper.SetConfigType("toml") //设置格式
var tomlExample = []byte(`name="bing"`)//必须要是toml格式

if err := viper.ReadConfig(bytes.NewBuffer(tomlExample)); err != nil {
    panic(err)
}
fmt.Println(viper.Get("name")) //输出“bing”

监控Viper文件

viper支持监听配置文件,并会在配置文件发生变化,重新读取配置文件和回调函数,这样可以避免每次配置变化时,都需要重启启动应用的麻烦。

viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
    fmt.Println(e.Name)
    fmt.Println(viper.Get("mysql.password"))
})

如果被监听的配置文件是config.yaml,当config.yaml的内容发生变化时就会调用回调函数,回调函数把e.Name输出,这个e.Name就是config.yaml这个文件名,当然也可以输出自己想要的信息。

最后,关于viper的功能还有很多,由于项目中还没有遇到其他类型的需求,所以暂时总结这么多,关于viper的其他功能等以后再来补充。


参考链接:

  1. 配置解析神器viper使用详解 - 掘金
  2. Go语言配置管理神器——Viper中文教程
  3. viper操作文档 - 掘金

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【MySQL】Mycat

文章目录 什么是Mycat为什么要用Mycatmycat能干什么各数据库中间件对比Mycat原理数据库中间件逻辑库逻辑表分片表分片规则全局表ER表非分片表分片节点节点主机mycat安装mycat核心配置schema.xmlserver.xmlrule.xml加密明文密码(可选) MyCat读写分离垂直拆…

OpenCV中的图像处理3.11(10) OpenCV中的图像变换

目录 3.11 OpenCV中的图像变换3.11.1 傅里叶变换目标理论Numpy中的傅里叶变换OpenCV中的傅立叶变换DFT的性能优化为什么Laplacian是一个高通滤波器?其他资源 翻译及二次校对:cvtutorials.com 编辑者:廿瓶鲸(和鲸社区Siby团队成员&…

2.3 YARN伪分布式集群搭建

任务目的 重点掌握 YARN 集群的相关配置学会启动和关闭 YARN 集群的两种方式能够使用 jps 命令查看进程的启动情况能够通过 UI 查看 YARN 集群的运行状态任务清单 任务1:YARN 集群主要配置文件讲解任务2:YARN 集群测试任务步骤 任务1:YARN 集群主要配置文件讲解 1.1 配置环…

基于多尺度图神经网络的流场预测,实现精度与速度的平衡

项目简介 本项目来源于飞桨AI for Science共创计划的论文复现赛题,复现论文为《AMGNET: multi-scale graph neural networks for flow field prediction》。该论文主要采用图神经网络,因为在计算流体力学中计算域被网格离散化,这与图结构天然…

将PDF1页分割为4页

运行效果 原始PDF 分割后PDF 一、python代码(用的是python3.9.0版本) import os import tempfile from pdf2image import convert_from_path from PIL import Image from PyPDF2 import PdfReader, PdfWriterdef split_pdf_page(pdf_path, output_path…

4G开发板-安卓手机开发套件-MTK主板开发板定制

开发板是一种用于嵌入式系统开发的电路板,它包含了各种硬件组件,如中央处理器、存储器、输入设备、输出设备、数据通路/总线以及外部资源接口等。为了满足特定的开发需求,嵌入式系统开发者通常会根据项目要求来定制开发板,当然用户…

2023年前端面试高频考点ES6

目录 ES6新增 数据类型 基本数据类型 引用数据类型 Null,NaN,Undefined toString,valueOf ,,Object.is() 判断数据类型:typeof运算符,instance of运算符,isPrototypeOf() 方…

数据分析第11课pandas时间序列(上+下)-第12期15,16课

数据分析思维:有逻辑性, 课前练习1 各大平台相继推出和迭代付费会员策略,如优酷会员、京东PLUS会员、网易云音乐黑胶VIP等,通过提供丰富的权益吸引用户成为付 费会员,提升用户黏性和忠诚度。请围绕付费会员回答以下问题: 以网易云音乐黑胶VIP为例,运营同学希望推出活动…

k8s 使用helm安装longhorn存储控制器

1.安装helm 参考:k8s helm安装使用_Apex Predator的博客-CSDN博客 2.配置基础环境 安装longhorn存储控制器需要用到iSCSI工具,所以需要在k8s所有节点上安装 yum -y install iscsi-initiator-utils 3.安装longhorn 3.1配置helm镜像源 helm repo ad…

kafka Ar 、ISR 、 OSR 已分配副本 同步中副本 、不同步副本 Controller 执行leader 重新分配

目录 Ar 、ISR 、 OSR 已分配副本 同步中副本 、不同步副本 Controller 执行leader 重新分配 Ar 、ISR 、 OSR 已分配副本 同步中副本 、不同步副本 AR分区所有已分配副本 ISR 在同步中的副本OSR 不同步副本 如果有一个节点挂掉,分区领导会渠道其他地方当上领导…

Git的理解以及在IDEA中的使用

什么是版本控制 版本控制是指记录一段时间内对一个文件或一组文件的更改的系统,称为“版本”。换句话说,这些版本将帮助您跟踪代码/项目中的更改,如果需要,还可以撤消这些更改。 当处理较大的项目时,这种能够比较、区…

“RAID0 vs RAID1 vs RAID5 vs RAID6 vs RAID10:哪种RAID级别最适合你的需求?“

概要: RAID(Redundant Array of Independent Disks)是一种数据存储技术,可以将多个硬盘组合起来以提高性能、可靠性和容错能力。下面是几种常见的RAID级别,以及它们的用途和特点。 目录 RAID 0RAID 1RAID 5RAID 6RAID…

navicat 怎么导入运行bak文件,详细教程

文章目录 一、新建数据库,点击高级设置访问权限二、点击SQL Server备份三、右击空白,点击从文件还原四、找到备份的bak文件五、 点击“高级”选项六、然后点击 生产SQL,最后点 还原 一、新建数据库,点击高级设置访问权限 二、点击…

Opencv-python 将图片中某段HSV范围内的所有像素去除,用白色替换

文章目录 前言一、效果二、代码1.思路2.代码解释 总结 前言 本次实验要求将模拟飞行座舱图像中的HUD绿色字体去掉,并且用白色来替代,最终输出没有绿色字体的图片,用于下一步的某种图像算法的输入。 一、效果 二、代码 1.思路 将一张图片中的…

经验教训:微服务设计时的五条宝贵经验

微服务架构的新挑战 在著名软件著作《人月神话》中提到,软件世界没有“银弹”,这句话当然适用于架构领域,随着从单体架构过渡到微服务架构,因为将原有系统打散,给系统增加了许多不稳定因素。 单体架构向微服务架构转变…

【服务器数据恢复】断电导致RAID无法找到存储设备的数据恢复案例

服务器数据恢复环境: HP EVA存储,6块SAS硬盘组建的raid5磁盘阵列。上层操作系统是WINDOWS SERVER。该存储为公司内部文件服务器使用。 服务器故障&分析: 在遭遇两次意外断电后,设备重启时raid提示“无法找到存储设备”。管理员…

值得推荐收藏的 9个免费PDF转PPT的方法

随着现在工作和学习越来越多涉及到电子文件,PDF格式已经成为了一种非常重要的文件格式。但有时候需要将PDF文件转换为PPT格式,因为PPT格式更适合用于演示和公开演讲等场合。而转换PDF文件到PPT格式则需要使用专用工具。以下是9个免费的PDF转PPT的方法介绍…

蓝牙耳机都能打电话吗,分享几款通话效果不错的骨传导耳机

骨传导耳机的兴起是近几年来才出现的新概念,骨传导耳机也是近几年来才开始流行起来,在我看来骨传导耳机的兴起是科技进步的产物。随着蓝牙耳机技术和设备的发展,蓝牙耳机也越来越普及,但是也给用户带来了很多困扰。而骨传导耳机就…

好用的电容笔有哪些推荐?性价比高的触控笔

电容笔的选购对新手来说难度很大,看到网友们都在讨论电容笔什么牌子的好用,电容笔怎么挑选?小编今天也来详细解答这个问题,盘点四款好用的平价电容笔,如果你想知道性价比高电容笔推荐哪些,那这篇文章一定不…

什么是 Vue 的片段(Fragment)?如何使用片段?

什么是 Vue 的片段(Fragment)?如何使用片段? 在 Vue 2.6.0 版本中,新增了一个特性:片段(Fragment)。片段是一种特殊的组件,可以让开发者在不增加额外节点的情况下渲染多…