当前位置: 首页 > web >正文

golang -- viper

前言

Viper 是适用于Go应用程序(包括Twelve-Factor App)的完整配置解决方案。它被设计用于在应用程序中工作,并且可以处理所有类型的配置需求和格式

说白了 就是把配置信息存放到 viper 里面,需要用到配置信息的时候再从 viper 中拿出来

读取配置

设置默认值

viper.SetDefault("fileDir", "./")

意思就是,fileDir 是配置文件里面的一个配置,现在我要读取这个配置项,但是这个配置不存在,那么就读取默认值 ” ./ “

读取配置文件

在这里插入代码片//读取配置文件
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath("/etc/appname/")
viper.AddConfigPath("$HOME/.appname")
viper.AddConfigPath(".")

这几行代码就是在告诉 Viper 到哪些地方去找配置文件

查找并读取配置文件

err := viper.ReadInConfig() //查找并读取配置文件

这一行就是告诉 Viper 去查找并读取你之前指定的配置文件
err 是为了判断读取配置时是否发生错误,若发生错误则返回

如果出错了,想知道是不是因为 找不到配置文件 引发的错误,可以这样判断

if err != nil{if _, ok := err.(viper.ConfigFileNotFoundError); ok {//配置文件未找到错误,可以自己决定要不要忽略}else{//配置文件被找到,但有其他的错误}
}

写入配置

当然了,可以读取配置文件,也可以写入配置文件

1. viper.WriteConfig()

  • 作用:把当前 Viper 内存里的配置 写入到默认配置文件(即你用 ReadInConfig() 读到的那个文件),如果文件不存在,会报错

    viper.Set("app.name", "myApp")   // 修改配置
    err := viper.WriteConfig()       // 写回文件
    if err != nil {fmt.Println("写入失败:", err)
    }
    

    viper.Set("app.name", "myApp") = 在内存里把 app.name 这个配置项的值改成了 “myApp”,但是需要注意的是,Set 只是改变了内存中 app.name 这个配置项的值,要改变 viper 中 app.name 这个配置项的值,还需要执行
    viper.WriteConfig()
    这里写回文件,写到的是前面读取到的配置文件
    viper.SetConfigName("config")


  1. viper.SafeWriteConfig()
  • 作用:和 WriteConfig 类似,但是 如果 预定义路径不存在,则报错;存在,则不会覆盖当前的配置文件

    err := viper.SafeWriteConfig()
    

  1. viper.WriteConfigAs(filename string)
  • 作用:把 Viper 内存里的当前配置内容,写到指定的 filename 文件里,如果文件已存在,会覆盖

    err := viper.WriteConfigAs("new_config.yaml")
    

  1. viper.SafeWriteConfigAs(filename string)
  • 作用:和 WriteConfigAs 类似,但如果文件已经存在,会报错不会覆盖

    err := viper.SafeWriteConfigAs("new_config.yaml")
    

监控并重新读取配置文件

Viper 支持在运行时实时读取配置文件的功能,可以理解为 边改边自动更新
有两种方式可以实现

//实时监控配置文件的变化
viper.WatchConfig()
//当配置变化之后调用的一个回调函数
viper.OnConfigChange(func(e fsnotify.Event) {//配置文件发生变更之后会调用的回调函数fmt.Println("Config file changed:", e.Name)
})

注册和使用别名

别名允许多个键引用单个值

//设置别名
viper.RegisterAlias("a1", "a2")

给 a2 起别名 a1

环境变量

  1. viper.AutomaticEnv()

    开启 自动绑定环境变量模式

    意思是:当你调用 viper.Get(“XXX”) 时,如果配置文件里没有这个 key,它会去 系统环境变量 里找同名的环境变量


  1. viper.BindEnv("a1")

    手动绑定某个 key 和环境变量

    比如你绑定了 a1,那么之后 viper.Get(“a1”) 会优先去环境变量里找 A1(或者根据前缀规则去找)

    BindEnv("a1") 的意思是,告诉 Viper 当我读取 配置项 a1 时,如果在环境变量里能找到对应的值,就用环境变量的值覆盖

    换句话说,它把配置 key a1 和环境变量绑在了一起

    1. 大小写关系
      环境变量名通常是 大写,而配置 key 一般是 小写
      所以 Viper 内部会自动把 “a1” 映射成 “A1” 来找环境变量

      例如:
      export A1=hello
      然后 Go 代码:

    	viper.BindEnv("a1")fmt.Println(viper.GetString("a1"))
    

    输出就是:

    hello
    
    1. 显式绑定环境变量名

      也可以 显式绑定环境变量名:

      viper.BindEnv("a1", "MY_CUSTOM_ENV")
      

      这样,配置项 “a1” 对应的环境变量就不再是 “A1”,而是 MY_CUSTOM_ENV


  1. viper.SetEnvPrefix("appname")

    设置一个环境变量的前缀

    有了这个前缀,viper 会去找 APPNAME_A1 这样的环境变量,而不是直接找 A1

    举例:
    export APPNAME_A1=123

    那么直接viper.Get("a1")就能拿到 123


  2. viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

    这是一个替换器,把配置 key 里的 . 转成 _,方便和环境变量对应

    因为环境变量一般不支持 .,所以要写:
    export APPNAME_DATABASE_HOST=127.0.0.1
    然后你在代码里 viper.Get("database.host") 就能拿到 127.0.0.1


  3. viper.AllowEmptyEnv(true)

    允许环境变量为空字符串也算“合法存在”

    默认情况下,如果环境变量存在但是为空,viper 可能会忽略它。加上这个就不会被忽略

使用 Flags

命令行参数是什么

平时我们运行程序时,可以带一些参数:

./app --port 8080 --config ./config.yaml``
- --port 8080 就是告诉程序:端口改成 8080
- --config ./config.yaml 是告诉程序:用 config.yaml 这个配置文件

如果不加这些参数,程序就会使用默认值

Go 里有几种方式处理命令行参数

Go 原生有 flag 包,比如:

port := flag.Int("port", 1138, "Port to run the server on")
flag.Parse()
fmt.Println(*port)

运行 ./app --port 8080,就会打印 8080。

但是 flag 比较简单,缺少子命令、分组管理等功能

Cobra:更强大的命令行框架

Cobra 提供了“命令 + 参数”的模式,比如:

./app server --port 8080
./app client --addr localhost:1234

Cobra 的典型写法:

var serverCmd = &cobra.Command{Use:   "server",Short: "Run the server",Run: func(cmd *cobra.Command, args []string) {// 这里写启动逻辑},
}

解释:

  1. Use

Use: "server",

表示命令的名字

比如,在命令函输入 myapp server,就会执行 Run 里面的函数


  1. Short

Short: "Run the server",

当用户执行 myapp help 或 myapp server -h 的时候,就会显示这一行

可以想象为路边的站牌,就是帮助信息


  1. Run

Run: func(cmd *cobra.Command, args []string) {// 这里写启动逻辑 },

这是命令真正执行的逻辑,当用户在命令行输入 myapp server 的时候,Cobra 就会调用这里的函数

举例:
cmd 参数是当前这个命令对象,args 是命令行后面跟的参数(比如 myapp server 8080 里,args 就是 [“8080”])


Viper 具有绑定到标志的能力。具体来说,Viper 库支持 Cobra 库中使用的 Pflag

BindEnv 类似,该值不是在调用绑定方法时设置的,而是在访问该方法时设置的。这意味着可以根据需要进行绑定

对于单个标志,BindPFlag() 方法提供此功能

serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))

serverCmd.Flags().Int("port", 1138, "Port to run Application server on")

  1. serverCmd.Flags()
  • 取到 serverCmd(一个 *cobra.Command)的 FlagSet
  • FlagSet 就是存放命令行参数的地方
  1. Int(“port”, 1138, “Port to run Application server on”)
  • 给这个 serverCmd 注册了一个命令行参数:
    • 名字:port
    • 默认值:1138
    • 说明:“Port to run Application server on”(打印 --help 时会显示)
  • 之后你在命令行里就能写 --port=8080 来覆盖默认值

viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))

  1. serverCmd.Flags().Lookup(“port”)
  • 找到刚才定义的 port 这个 flag
  1. viper.BindPFlag(“port”, …)
  • 把这个 flag 绑定到 Viper 的配置系统中,key 是 “port”
  • 意味着之后你用 viper.GetInt(“port”) 就能拿到最终的值(无论是默认值 1138,还是用户通过 --port 设置的值)
http://www.xdnf.cn/news/19650.html

相关文章:

  • Go语言运维实用入门:高效构建运维工具
  • 洽洽的“成本龙卷风”与渠道断层
  • MVC问题记录
  • Python备份实战专栏第5/6篇:Docker + Nginx 生产环境一键部署方案
  • 【机器学习入门】4.4 聚类的应用——从西瓜分类到防控,看无监督学习如何落地
  • Mac上如何安装mysql
  • 阿里云代理商:轻量应用服务器介绍及搭建个人博客教程参考
  • 【赵渝强老师】阿里云大数据MaxCompute的体系架构
  • Git基础使用和PR贡献
  • 02-Media-1-acodec.py 使用G.711编码和解码音频的示例程序
  • 电子电气架构 --- 智能电动车EEA电子电气架构(上)
  • 时序数据库IoTDB:为何成为工业数据管理新宠?
  • (Mysql)MVCC、Redo Log 与 Undo Log
  • 《探索C++11:现代C++语法的性能革新(上篇)》
  • C++11 ——— lambda表达式
  • 前端必看:为什么同一段 CSS 在不同浏览器显示不一样?附解决方案和实战代码
  • 血缘元数据采集开放标准:OpenLineage Guides 使用 Apache Airflow® 和 OpenLineage + Marquez 入门
  • 使用Spring Boot对接印度股票市场API开发实践
  • Linux初始——Vim
  • [VLDB 2025]阿里云大数据AI平台多篇论文被收录
  • Matrix-Breakout: 2 Morpheus靶场渗透
  • docker本地部署dify,nginx80端口占用的报错
  • 环境搭建汇总
  • Burp Suite 插件 | 提供强大的框架自动化安全扫描功能。目前支持1000+POC、支持动态加载POC、指定框架扫描。
  • 代码随想录刷题Day47
  • 前端测试深度实践:从单元测试到E2E测试的完整测试解决方案
  • 医疗AI时代的生物医学Go编程:高性能计算与精准医疗的案例分析(八)
  • 华宇TAS应用中间件与长城科技两款产品完成兼容互认证
  • 卷积神经网络训练全攻略:从理论到实战
  • 矩阵中寻找好子矩阵