使用毒蛇从envfile读取配置

问题描述

我不太了解毒蛇的工作原理。 这是我的代码

configuration.go

var Config *Configuration

type ServerConfiguration struct {
    Port string
}

type Configuration struct {
    Server   ServerConfiguration
}

func Init() {
    var configuration *Configuration
    viper.SetConfigFile(".env")
    viper.AutomaticEnv()
    if err := viper.ReadInConfig(); err != nil {
        log.Fatalf("Error reading config file,%s",err)
    }

    err := viper.Unmarshal(&configuration)
    if err != nil {
        log.Fatalf("Unable to decode into struct,%v",err)
    }

    Config = configuration
}

func GetConfig() *Configuration {
    return Config
}

.env SERVER_PORT=:4747

问题是解组不起作用 例如,当我使用configuration.Server.Port时,它是空的

解决方法

spf13/viper主要使用mapstructure包在一种本机Go类型与另一种本机Go类型之间进行转换,即在取消编组时。软件包内部使用map[string]interface{}类型存储您的配置(请参见viper.go - L1327)。之后,根据配置类型(您的情况为env),vi蛇会调用正确的解析包来存储您的配置值。对于envfile类型,它使用subosito/gotenv来放入上述映射类型(请参见viper.go - L1501

问题的症结在于如何使毒蛇在映射到您选择的结构的地图中解组此配置。这就是mapstructure软件包的出现位置,可将地图解组为您定义的嵌套结构。此时,您剩下两个选择

  1. 将配置解编为map[string]interface{}类型,然后使用mapstructure放入适当的结构
  2. 使用DecodeHookFunc作为方法的第二个参数来解组配置(请参见viper.go - L904

出于简单的原因,您可以做一个,根据我在您的示例中复制的一个简单示例,可以在下面完成

package main

import (
    "fmt"
    "github.com/mitchellh/mapstructure"
    "github.com/spf13/viper"
)

type ServerConfiguration struct {
    Port string `mapstructure:"server_port"`
}

type Configuration struct {
    Server ServerConfiguration `mapstructure:",squash"`
}

func main() {
    var result map[string]interface{}
    var config Configuration
    viper.SetConfigFile(".env")
    if err := viper.ReadInConfig(); err != nil {
        fmt.Printf("Error reading config file,%s",err)
    }

    err := viper.Unmarshal(&result)
    if err != nil {
        fmt.Printf("Unable to decode into map,%v",err)
    }

    decErr := mapstructure.Decode(result,&config)

    if decErr != nil {
        fmt.Println("error decoding")
    }

    fmt.Printf("config:%+v\n",config)
}

您可以根据实际用例定制此工作示例。有关嵌入结构的mapstructure squash标签的更多信息,请参见here