go语言中读取配置文件的方法总结

 更新时间:2023年08月29日 11:04:44   作者:fliter  
这篇文章主要为大家详细介绍了go语言中读取配置文件的几个常见方法,文中的示例代码讲解详细,具有一定的借鉴价值,需要的小伙伴可以参考下

使用viper管理配置

  • 支持多种配置文件格式,包括 JSON,TOML,YAML,HECL,envfile,甚至还包括Java properties
  • 支持为配置项设置默认值
  • 可以通过命令行参数覆盖指定的配置项
  • 支持参数别名

viper按照这个优先级(从高到低)获取配置项的取值:

  • explicit call to Set: 在代码逻辑中通过viper.Set()直接设置配置项的值
  • flag:命令行参数
  • env:环境变量
  • config:配置文件
  • key/value store:etcd或者consul
  • default:默认值

按照这个优先级(从高到低)获取配置项的取值:

  • explicit call to Set: 在代码逻辑中通过viper.Set()直接设置配置项的值
  • flag:命令行参数
  • env:环境变量
  • config:配置文件
  • key/value store:etcd或者consul
  • default:默认值

优先级

验证一下 viper.Set() 的优先级高于 配置文件

package main
import (
	"fmt"
	"github.com/spf13/viper"
)
func main() {
	loadConfig()
}
func loadConfig() {
	configVar := "shuang-config.yaml"
	configVar = "" // 这行如果注释掉,则从指定的configVar读取配置文件;否则就各种条件去找了
	viper.Set("Global.Source", "优先级最高")
	if configVar != "" {
		// SetConfigFile 显式定义配置文件的路径、名称和扩展名。
		// Viper 将使用它而不检查任何配置路径。
		viper.SetConfigFile(configVar)
	} else {
		// 如果没有显式指定配置文件,则
		// 会去下面的路径里找文件名`cui-config`的文件  name of config file (without extension)
		// 按照 []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}的顺序(居然还支持Java用的properties)
		viper.SetConfigName("cui-config")
		viper.AddConfigPath("/etc/myapp") // 找寻的路径
		viper.AddConfigPath("$HOME/.myapp/")
		viper.AddConfigPath(".")
	}
	err := viper.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("error reading config: %s", err))
	}
	fmt.Printf("到底用的是哪个配置文件: '%s'\n", viper.ConfigFileUsed())
	fmt.Printf("Global.Source这个字段的值为: '%s'\n", viper.GetString("global.source"))
}

输出:

到底用的是哪个配置文件: '/Users/fliter/config-demo/cui-config.yaml'
Global.Source这个字段的值为: '优先级最高'

验证一下 环境变量 的优先级高于 配置文件

package main
import (
	"fmt"
	"github.com/spf13/viper"
)
func main() {
	loadConfig()
}
func loadConfig() {
	configVar := "shuang-config.yaml"
	configVar = "" // 这行如果注释掉,则从指定的configVar读取配置文件;否则就各种条件去找了
	viper.Set("Global.Source", "优先级最高")
	viper.AutomaticEnv()
	if configVar != "" {
		// SetConfigFile 显式定义配置文件的路径、名称和扩展名。
		// Viper 将使用它而不检查任何配置路径。
		viper.SetConfigFile(configVar)
	} else {
		// 如果没有显式指定配置文件,则
		// 会去下面的路径里找文件名`cui-config`的文件  name of config file (without extension)
		// 按照 []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}的顺序(居然还支持Java用的properties)
		viper.SetConfigName("cui-config")
		viper.AddConfigPath("/etc/myapp") // 找寻的路径
		viper.AddConfigPath("$HOME/.myapp/")
		viper.AddConfigPath(".")
	}
	err := viper.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("error reading config: %s", err))
	}
	fmt.Printf("到底用的是哪个配置文件: '%s'\n", viper.ConfigFileUsed())
	fmt.Printf("LANG这个字段的值为: '%s'\n", viper.GetString("LANG"))
}

viper.AutomaticEnv()会绑定所有环境变量,

如果只希望绑定特定的,可以使用SetEnvPrefix("global.source", "MYAPP_GLOAL_SOURCE"),注意这个函数不会自动加上MYAPP的前缀.

验证一下 命令行参数的优先级高于 配置文件

viper可以配合pflag来使用,pflag可以理解为标准库flag的一个增强版,viper可以绑定到pflag上

和cobra,viper一样,pflag也是同一作者的作品

验证一下 默认值的优先级低于 配置文件

package main
import (
	"fmt"
	"github.com/spf13/viper"
)
func main() {
	loadConfig()
}
func loadConfig() {
	configVar := "shuang-config.yaml"
	configVar = "" // 这行如果注释掉,则从指定的configVar读取配置文件;否则就各种条件去找了
	//viper.Set("Global.Source", "优先级最高")
	viper.AutomaticEnv()
	viper.SetDefault("Global.Source", "优先级最低")
	if configVar != "" {
		// SetConfigFile 显式定义配置文件的路径、名称和扩展名。
		// Viper 将使用它而不检查任何配置路径。
		viper.SetConfigFile(configVar)
	} else {
		// 如果没有显式指定配置文件,则
		// 会去下面的路径里找文件名`cui-config`的文件  name of config file (without extension)
		// 按照 []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}的顺序(居然还支持Java用的properties)
		viper.SetConfigName("cui-config")
		viper.AddConfigPath("/etc/myapp") // 找寻的路径
		viper.AddConfigPath("$HOME/.myapp/")
		viper.AddConfigPath(".")
	}
	err := viper.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("error reading config: %s", err))
	}
	fmt.Printf("到底用的是哪个配置文件: '%s'\n", viper.ConfigFileUsed())
	fmt.Printf("Global.Source这个字段的值为: '%s'\n", viper.GetString("Global.Source"))
}

Watch机制(配置更新后 热加载)

该机制可以监听配置文件的修改, 这样就实现了热加载,修改配置后,无需重启服务

  • 对于本地文件,是通过fsnotify实现的,然后通过一个回调函数去通知应用来reload;
  • 对于Remote KV Store,目前只支持etcd,做法比较ugly,(5秒钟)轮询一次 而不是watch api
package main
import (
	"fmt"
	"time"
	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
)
func main() {
	loadConfig()
}
func loadConfig() {
	configVar := "shuang-config.yaml"
	configVar = "" // 这行如果注释掉,则从指定的configVar读取配置文件;否则就各种条件去找了
	if configVar != "" {
		// SetConfigFile 显式定义配置文件的路径、名称和扩展名。
		// Viper 将使用它而不检查任何配置路径。
		viper.SetConfigFile(configVar)
	} else {
		// 如果没有显式指定配置文件,则
		// 会去下面的路径里找文件名`cui-config`的文件  name of config file (without extension)
		// 按照 []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}的顺序(居然还支持Java用的properties)
		viper.SetConfigName("cui-config")
		viper.AddConfigPath("/etc/myapp") // 找寻的路径
		viper.AddConfigPath("$HOME/.myapp/")
		viper.AddConfigPath(".")
	}
	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		fmt.Printf("配置文件 %s 发生了更改!!! 最新的Global.Source这个字段的值为 %s:", e.Name, viper.GetString("Global.Source"))
	})
	err := viper.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("error reading config: %s", err))
	}
	fmt.Printf("到底用的是哪个配置文件: '%s'\n", viper.ConfigFileUsed())
	fmt.Printf("Global.Source这个字段的值为: '%s'\n", viper.GetString("Global.Source"))
	time.Sleep(10000e9)
}

Go viper 配置文件读取工具

动态获取配置文件(viper)

configor

Configor: 一个Golang配置工具,支持YAML,JSON,TOML,Shell环境,支持热加载

出自jinzhu大佬

package main
import (
	"fmt"
	"github.com/jinzhu/configor"
)
type Config struct {
	APPName string `default:"app name"`
	DB      struct {
		Name     string
		User     string `default:"root"`
		Password string `required:"true" env:"DBPassword"`
		Port     uint   `default:"3306"`
	}
	Contacts []struct {
		Name  string
		Email string `required:"true"`
	}
}
func main() {
	var conf = Config{}
	err := configor.Load(&conf, "config.yml")
	// err := configor.New(&configor.Config{Debug: true}).Load(&conf, "config.yml")  // 测试模式,也可以通过环境变量开启测试模式(CONFIGOR_DEBUG_MODE=true go run main.go ),这样就无需修改代码
	//err := configor.New(&configor.Config{Verbose: true}).Load(&conf, "config.yml") // 模式,也可以通过环境变量开启详细模式(CONFIGOR_VERBOSE_MODE=true go run main.go ),这样就无需修改代码
	if err != nil {
		panic(err)
	}
	fmt.Printf("%v \n", conf)
}

开启 测试模式 or 详细模式

既可以在代码中显式开启,如 err := configor.New(&configor.Config{Debug: true}).Load(&conf, "config.yml")

也可以通过环境变量开启,如 CONFIGOR_DEBUG_MODE=true go run main.go

加载多个配置文件

// application.yml 的优先级 大于 database.json, 排在前面的配置文件优先级大于排在后的的配置
configor.Load(&Config, "application.yml", "database.json")

根据环境变量加载配置文件 or 从shell加载配置项

详细可参考 Golang Configor 配置文件工具

热更新

package main
import (
	"fmt"
	"time"
	"github.com/jinzhu/configor"
)
type Config struct {
	APPName string `default:"app name"`
	DB      struct {
		Name     string
		User     string `default:"root"`
		Password string `required:"true" env:"DBPassword"`
		Port     uint   `default:"3306"`
	}
	Contacts []struct {
		Name  string
		Email string `required:"true"`
	}
}
func main() {
	var conf = Config{}
	// reload模式,可实现热加载
	err := configor.New(&configor.Config{
		AutoReload:         true,
		AutoReloadInterval: time.Second,
		AutoReloadCallback: func(config interface{}) {
			// config发生变化后出发什么操作
			fmt.Printf("配置文件发生了变更%#v\n", config)
		},
	}).Load(&conf, "config.yml")
	// 无reload模式
	//err := configor.Load(&conf, "config.yml")
	// err := configor.New(&configor.Config{Debug: true}).Load(&conf, "config.yml")  // 测试模式,也可以通过环境变量开启测试模式(CONFIGOR_DEBUG_MODE=true go run main.go ),这样就无需修改代码
	//err := configor.New(&configor.Config{Verbose: true}).Load(&conf, "config.yml") // 模式,也可以通过环境变量开启详细模式(CONFIGOR_VERBOSE_MODE=true go run main.go ),这样就无需修改代码
	if err != nil {
		panic(err)
	}
	fmt.Printf("%v \n", conf)
	time.Sleep(100000e9)
}

完整代码

到此这篇关于go语言中读取配置文件的方法总结的文章就介绍到这了,更多相关go读取配置文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • go redis实现滑动窗口限流的方式(redis版)

    go redis实现滑动窗口限流的方式(redis版)

    这篇文章主要介绍了go redis实现滑动窗口限流的方式(redis版),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • Go实现分布式系统高可用限流器实战

    Go实现分布式系统高可用限流器实战

    这篇文章主要为大家介绍了Go实现分布式系统高可用限流器实战,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Go语言中的自定义函数类型的实现

    Go语言中的自定义函数类型的实现

    在Go语言中,函数类型是一种将函数作为值的数据类型,本文主要介绍了Go语言中的自定义函数类型,具有一定的参考价值,感兴趣的可以了解一下
    2023-09-09
  • Golang 字符串转time类型实现

    Golang 字符串转time类型实现

    本文主要介绍了Golang 字符串转time类型实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • GO语言基本类型String和Slice,Map操作详解

    GO语言基本类型String和Slice,Map操作详解

    这篇文章主要为大家介绍了GO语言基本类型String和Slice,Map操作示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • Windows环境下vscode-go安装笔记(不支持32位)

    Windows环境下vscode-go安装笔记(不支持32位)

    这篇文章主要介绍了Windows环境下vscode-go安装笔记(不支持32位),需要的朋友可以参考下
    2017-02-02
  • golang实现mysql数据库事务的提交与回滚

    golang实现mysql数据库事务的提交与回滚

    这篇文章主要介绍了golang实现mysql数据库事务的提交与回滚,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • GO利用channel协调协程的实现

    GO利用channel协调协程的实现

    本文主要介绍了GO利用channel协调协程的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • 详解Golang中哪些类型可以作为map的key

    详解Golang中哪些类型可以作为map的key

    在 Go 语言中,map 是一种内置的关联数据结构类型,由一组无序的键值对组成,每个键都是唯一的,并与一个对应的值相关联,本文将详细介绍哪些类型的变量可以作为 map 的键,并通过实例进行说明,感兴趣的朋友可以参考下
    2024-01-01
  • go使用支付宝沙箱实现支付宝支付的操作步骤

    go使用支付宝沙箱实现支付宝支付的操作步骤

    支付宝沙箱支付是支付宝提供的一个测试环境,用于开发者在不影响真实交易的情况下进行支付接口的开发和调试,本文给大家介绍了go使用支付宝沙箱实现支付宝支付的操作步骤,文中有详细的代码示例和图文供大家参考,需要的朋友可以参考下
    2024-03-03

最新评论