golang 使用 viper 加载配置文件 自动反序列化到结构

文章博客地址:golang 使用 viper 加载配置 自动反序列化到结构

  • golang使用 viper 无需设置 mapstructure tag 根据配置文件后缀 自动返序列化到结构
  • 解决结构有下划线的字段解析不成功问题

viper 正常加载配置文件

golang viper 其中可以用来 查找、加载和反序列化JSON、TOML、YAML、HCL、INI、envfile和格式的配置文件

配置文件 test_toml.toml

ini 复制代码
http_addr = ":8082"
grpc_addr = ":8083"
jaeger_url= "http://localhost:14268/api/traces"
tracing= true

golang代码

golang 复制代码
type ConfigTest struct {
	HttpAddr  string `json:"http_addr" toml:"http_addr" yaml:"http_addr"`
	GrpcAddr  string `json:"grpc_addr" toml:"grpc_addr" yaml:"grpc_addr"`
	JaegerUrl string `json:"jaeger_url" toml:"jaeger_url" yaml:"jaeger_url" mapstructure:"jaeger_url"`
	Tracing   bool   `toml:"tracing"  json:"tracing" yaml:"tracing" ` // opentelemetry tracing
}

// jaeger 加载配置文件
func TestSourceFile_Unmarshal(t *testing.T) {
	filePath := "./test_toml.toml"
	viper.SetConfigFile(filePath)
	if err := viper.ReadInConfig(); err != nil {
		t.Error(err)
	}

	c := &ConfigTest{}
	if err := viper.Unmarshal(c); err != nil {
		t.Error(err)
	}
	logger.Infow("Unmarshal file sucess", "v", c)
}

打印返序列化的配置结构

shell 复制代码
{"level":"info","ts":"2023-08-27T21:35:27.041+0800","caller":"config/source_file_test.go:31","msg":"Unmarshal file sucess","v":{"http_addr":"","grpc_addr":"","jaeger_url":"http://localhost:14268/api/traces","tracing":true}}

可以看到带下划线的字段,不加 mapstructure 标签,是不会反序列化

不加 mapstructure tag实现自动反序列化

查看viper Unmarshal 代码

golang 复制代码
func (v *Viper) Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error {
	return decode(v.AllSettings(), defaultDecoderConfig(rawVal, opts...))
}
func decode(input interface{}, config *mapstructure.DecoderConfig) error {
	decoder, err := mapstructure.NewDecoder(config)
	if err != nil {
		return err
	}
	return decoder.Decode(input)
}
func NewDecoder(config *DecoderConfig) (*Decoder, error) {
	if config.TagName == "" {
		config.TagName = "mapstructure"
	}
	// ...
}
  • 从代码看出 Viper使用的是 github.com/mitchellh/mapstructure来解析值
  • mapstructure 用于将通用的map[string]interface{}解码到对应的 Go 结构体中
  • 默认情况下,mapstructure 使用结构体中字段的名称做这个映射,不区分大小写,比如 Name 字段可以映射到 name、NAME、NaMe 等等
  • 如果没有指定 tagName ,则默认为 mapstructure,这也是为什么带下划线的字段不加 mapstructure 标签无法解析的原因
  • viper 中Unmarshal的第二个参数是可以指定 DecoderConfigOption 的,从而可以指定 tagName

viper根据文类型件自动解码到结构

  1. 读取文件后缀比如 toml
  2. 根据后缀设置 tagName
  3. 调用 viper.Unmarshal解析
golang 复制代码
func TestSourceFile_Unmarshal1(t *testing.T) {
	filePath := "./test_toml.toml"
	c := &ConfigTest{}
	if err := viperUnmarshal(c, filePath); err != nil {
		t.Error(err)
	}
	logger.Infow("Unmarshal file sucess", "v", c)
}

func viperUnmarshal(v interface{}, configPath string) error {
	var tagName string
	ext := filepath.Ext(configPath)
	if len(ext) > 1 {
		tagName = ext[1:]
	}
	// set decode tag_name, default is mapstructure
	decoderConfigOption := func(c *mapstructure.DecoderConfig) {
		c.TagName = tagName
	}
	cViper := viper.New()
	cViper.SetConfigFile(configPath)
	if err := cViper.ReadInConfig(); err != nil {
		return err
	}
	return cViper.Unmarshal(v, decoderConfigOption)
}
shell 复制代码
{"level":"info","ts":"2023-08-27T21:35:34.553+0800","caller":"config/source_file_test.go:40","msg":"Unmarshal file sucess","v":{"http_addr":":8082","grpc_addr":":8083","jaeger_url":"http://localhost:14268/api/traces","tracing":true}}

我已将viper加载配置集成进自己的项目,完整example 代码可以查看 source_file_test.go

相关推荐
MadPrinter7 分钟前
SpringBoot学习日记 Day11:博客系统核心功能深度开发
java·spring boot·后端·学习·spring·mybatis
dasseinzumtode7 分钟前
nestJS 使用ExcelJS 实现数据的excel导出功能
前端·后端·node.js
淦出一番成就10 分钟前
Java反序列化接收多种格式日期-JsonDeserialize
java·后端
Java中文社群12 分钟前
Hutool被卖半年多了,现状是逆袭还是沉寂?
java·后端
程序员蜗牛1 小时前
9个Spring Boot参数验证高阶技巧,第8,9个代码量直接减半!
后端
yeyong1 小时前
咨询kimi关于设计日志告警功能,还是有启发的
后端
库森学长1 小时前
2025年,你不能错过Spring AI,那个汲取了LangChain灵感的家伙!
后端·openai·ai编程
一朵筋斗云1 小时前
golang底层原理剖析
go
Java水解1 小时前
Spring Boot 启动流程详解
spring boot·后端
学历真的很重要1 小时前
Claude Code Windows 原生版安装指南
人工智能·windows·后端·语言模型·面试·go