golang -- viper

前言

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

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

读取配置

设置默认值

go 复制代码
viper.SetDefault("fileDir", "./")

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

读取配置文件

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

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

查找并读取配置文件

go 复制代码
err := viper.ReadInConfig() //查找并读取配置文件

这一行就是告诉 Viper 去查找并读取你之前指定的配置文件

err 是为了判断读取配置时是否发生错误,若发生错误则返回

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

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

写入配置

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

1. viper.WriteConfig()

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

    go 复制代码
    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 类似,但是 如果 预定义路径不存在,则报错;存在,则不会覆盖当前的配置文件

    go 复制代码
    err := viper.SafeWriteConfig()

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

    go 复制代码
    err := viper.WriteConfigAs("new_config.yaml")

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

    go 复制代码
    err := viper.SafeWriteConfigAs("new_config.yaml")

监控并重新读取配置文件

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

有两种方式可以实现

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

注册和使用别名

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

go 复制代码
//设置别名
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 代码:

    go 复制代码
    	viper.BindEnv("a1")
    	fmt.Println(viper.GetString("a1"))

    输出就是:

    go 复制代码
    hello
    1. 显式绑定环境变量名

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

      go 复制代码
      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

命令行参数是什么

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

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

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

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

Go 原生有 flag 包,比如:

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

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

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

Cobra:更强大的命令行框架

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

bash 复制代码
./app server --port 8080
./app client --addr localhost:1234

Cobra 的典型写法:

go 复制代码
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() 方法提供此功能

go 复制代码
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 设置的值)
相关推荐
IDC02_FEIYA3 小时前
魔域服务器多少钱一个月?魔域服务器配置要求及推荐
运维·服务器
DemonAvenger4 小时前
MySQL性能监控与分析工具使用指南:从入门到实战优化
数据库·sql·性能优化
张人玉4 小时前
SQLSERVER基本cmd操作命令
数据库·sqlserver
GottdesKrieges4 小时前
obdumper和obloader迁移OceanBase业务库(一):实施手册
数据库·oceanbase
类似不类似5 小时前
对比Mysql理解OceanBase中的租户设计
数据库·mysql·oceanbase
KIDAKN5 小时前
Redis 哨兵 (基于 Docker)
数据库·redis·缓存
静若繁花_jingjing5 小时前
面试_Mysql
数据库·mysql
_flierx5 小时前
【Linux】进程信号
linux·运维·服务器
2501_913981786 小时前
串口服务器技术详解:2025年行业标准与应用指南
运维·服务器·串口服务器