关于go:golang-使用-viper-加载配置文件-自动反序列化到结构

36次阅读

共计 2832 个字符,预计需要花费 8 分钟才能阅读完成。

文章博客地址: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

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)
}

打印返序列化的配置构造

{"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 代码

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 解析
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)
}
{"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

正文完
 0