基於viper的配置讀取

ice_moss發表於2022-11-12

文章介紹

本文我們將來介紹一下如何從第三方包viper來獲取配置檔案的配置資訊,以及開發模式下的配置和上線產品如何使用進行viper做配置對映

viper的安裝

go get github.com/spf13/viper

快速開始

例項目錄結構:

ch1
├── config.yaml    //配置檔案
└── main.go               //viper讀取配置

config.yaml:

name: 'user-web'
mysql:
  host: '127.0.0.1'
  port: 3306

main.go:

package main

import (
    "fmt"

    "github.com/spf13/viper"
)

type mysqlConfig struct {
    Host string `mapstructure:"host"`
    Port int    `mapstructure:"port"`
}

//ServerConfig 將配置檔案內容對映為struct
type ServerConfig struct {
    ServerName string      `mapstructure:"name"`
    SqlConfig  mysqlConfig `mapstructure:"mysql"`
}

func main() {
    //new物件
    v := viper.New()

    //讀取配置檔案
    v.SetConfigFile("viper_test/ch1/config.yaml")
    if err := v.ReadInConfig(); err != nil {
        panic(err)
    }
    ServerConfig := ServerConfig{}
    v.Unmarshal(&ServerConfig)
    fmt.Println(ServerConfig)
}

在上述程式碼中我們定義了兩個結構體:

type mysqlConfig struct {
    Host string `mapstructure:"host"`
    Port int    `mapstructure:"port"`
}

//ServerConfig 將配置檔案內容對映為struct
type ServerConfig struct {
    ServerName string      `mapstructure:"name"`
    SqlConfig  mysqlConfig `mapstructure:"mysql"`
}

這兩個結構體用來做配置對映,這裡使用mapstructure為配置做tag

完整程式碼:

package main

import (
    "fmt"

    "github.com/spf13/viper"
)

type mysqlConfig struct {
    Host string `mapstructure:"host"`
    Port int    `mapstructure:"port"`
}

//ServerConfig 將配置檔案內容對映為struct
type ServerConfig struct {
    ServerName string      `mapstructure:"name"`
    SqlConfig  mysqlConfig `mapstructure:"mysql"`
}

func main() {
    //new一個viper物件
    v := viper.New()

    //獲取配置檔案
    v.SetConfigFile("viper_test/ch1/config.yaml")

  //將配置讀入viper物件中
    if err := v.ReadInConfig(); err != nil {
        panic(err)
    }
    ServerConfig := ServerConfig{}

  //將讀取到的配置資訊對映至ServerConfig中
    v.Unmarshal(&ServerConfig)
    fmt.Println(ServerConfig)
}

輸出:

{user-web {127.0.0.1 3306}}

實時監控配置

viper為我們提供了實時監控配置的功能

v.WatchConfig()
    v.OnConfigChange(func(e fsnotify.Event) {
        fmt.Println("配置變化:", e)
        _ = v.ReadInConfig()
        v.Unmarshal(&ServerConfig)
        fmt.Println(ServerConfig)
    })

事例:

package main

import (
    "fmt"
    "time"

    "github.com/fsnotify/fsnotify"

    "github.com/spf13/viper"
)

type mysqlConfig struct {
    Host string `mapstructure:"host"`
    Port int    `mapstructure:"port"`
}

//ServerConfig 將配置檔案內容對映為struct
type ServerConfig struct {
    ServerName string      `mapstructure:"name"`
    SqlConfig  mysqlConfig `mapstructure:"mysql"`
}

func main() {
    //new物件
    v := viper.New()

    //讀取配置檔案
    v.SetConfigFile("viper_test/ch1/config.yaml")
    if err := v.ReadInConfig(); err != nil {
        panic(err)
    }
    ServerConfig := ServerConfig{}
    v.Unmarshal(&ServerConfig)
    fmt.Println(ServerConfig)

    v.WatchConfig()
    v.OnConfigChange(func(e fsnotify.Event) {
        fmt.Println("配置變化:", e)
        _ = v.ReadInConfig()
        v.Unmarshal(&ServerConfig)
        fmt.Println(ServerConfig)
    })

  //延遲程式退出時間
    time.Sleep(300 * time.Second)
}

執行程式後我們對port進行更改,會有如下輸出:

{user-web {127.0.0.1 3306}}
配置變化: WRITE         "viper_test/ch1/config.yaml"
{user-web {127.0.0.1 3303}}
配置變化: WRITE         "viper_test/ch1/config.yaml"
{user-web {127.0.0.1 3306}}

線上線下環境隔離

目錄結構:

ch02
├── config-debug.yaml   //開發環境
├── config-por.yaml            //線上環境
└── main.go

config-debug.yaml:

name: 'user-web-debug'
mysql:
  host: '127.0.0.1'
  port: 3306

config-por.yaml:

name: 'user-web'
mysql:
  host: '195.1.43.12'
  port: 2000

根據條件讀寫線上\線下配置並做監控

package main

import (
    "fmt"
    "time"

    "github.com/fsnotify/fsnotify"
    "github.com/spf13/viper"
)

//將配置檔案巢狀對映
type MysqlServerConfig struct {
    Host string `mapstructure:"host"`
    Port int    `mapstructure:"port"`
}

//將配置檔案內容對映為struct
type ServerConfig struct {
    ServerName string            `mapstructure:"name"`
    Mysql      MysqlServerConfig `mapstructure:"mysql"`
}

//透過環境變數,將線上線下環境隔離
func GetEnvInfo(env string) bool {
    viper.AutomaticEnv()
    return viper.GetBool(env)
}

func main() {
    debug := GetEnvInfo("MXSHOP_DEBUG")
    configFilePrefix := "config"

  //預設為線上配置
    configFileName := fmt.Sprintf("viper_test/ch02/%s-por.yaml", configFilePrefix)
    if debug {
        configFileName = fmt.Sprintf("viper_test/ch02/%s-debug.yaml", configFilePrefix)
    }

    v := viper.New()
    v.SetConfigFile(configFileName)
    if err := v.ReadInConfig(); err != nil {
        panic(err)
    }
    ServerConfig := ServerConfig{}
    if err := v.Unmarshal(&ServerConfig); err != nil {
        panic(err)
    }

    fmt.Println(ServerConfig)

    v.WatchConfig()
    v.OnConfigChange(func(e fsnotify.Event) {
        fmt.Println("配置變化:", e)
        _ = v.ReadInConfig()
        v.Unmarshal(&ServerConfig)
        fmt.Println(ServerConfig)
    })
    time.Sleep(300 * time.Second)
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章