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


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

    viper 正常加载配置文件

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

    配置文件 test_toml.toml

    http_addr = ":8082"
    grpc_addr = ":8083"
    jaeger_url= "http://localhost:14268/api/traces"
    tracing= true
    
    • 1
    • 2
    • 3
    • 4

    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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    打印返序列化的配置结构

    {"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}}
    
    • 1

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

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

    查看viper Unmarshal 代码

    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"
    	}
    	// ...
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 从代码看出 Viper使用的是 github.com/mitchellh/mapstructure来解析值
    • mapstructure 用于将通用的map[string]interface{}解码到对应的 Go 结构体中
    • 默认情况下,mapstructure 使用结构体中字段的名称做这个映射,不区分大小写,比如 Name 字段可以映射到
      name、NAME、NaMe 等等
    • 如果没有指定 tagName ,则默认为 mapstructure,这也是为什么带下划线的字段不加 mapstructure
      标签无法解析的原因
    • viper 中Unmarshal的第二个参数是可以指定 DecoderConfigOption 的,从而可以指定 tagName

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

    读取文件后缀比如 toml
    根据后缀设置 tagName
    调用 viper.Unmarshal解析

    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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
  • 相关阅读:
    Python3中的“加和”函数
    持安科技何艺:基于可信验证的应用访问安全模型 | CCS2023演讲分享
    简单粗暴提升yolov5小目标检测能力
    Windows右键菜单美化(适用版本:Win7-Win11) 奇怪的美化教程 #1
    我想说说长短链接
    配电房环境智能监控系统:守护电力设施,保障安全运行
    DSPE-PEG-Aldehyde,DSPE-PEG-CHO,磷脂-聚乙二醇-醛基一种疏水18碳磷脂
    在android中使用java反射机制的利弊分别是那些?与导入包名类名,androidmk追加对应jar包相比,二者差异是什么?
    软件测试技术之如何编写测试用例(6)
    css设置锚点与页面顶部保持一定距离
  • 原文地址:https://blog.csdn.net/m0_73728511/article/details/133749752