viper簡介
Viper是適用於Go應用程序的完整配置解決方案。它旨在在應用程序中工作,並且可以處理所有類型的配置需求和格式。它支持:
設置默認值
從JSON,TOML,YAML,HCL,envfile和Java屬性配置文件中讀取
實時觀看和重新讀取配置文件(可選)
從環境變量中讀取
從遠程配置系統(etcd或Consul)中讀取,並觀察更改
從命令行標志讀取
從緩沖區讀取
設置顯式值
可以將Viper視為滿足您所有應用程序配置需求的注冊表。
加載配置優先級
Viper會按照下面的優先級。每個項目的優先級都高於它下面的項目:
顯示調用Set設置值
命令行參數(flag)
環境變量
配置文件
key/value存儲
默認值
目錄結構
config.yaml
db:
username: mayanan
password: 123456789
host: 123.123.12.123
port: 33066
database: docker01
v: 88.88 # 將會覆蓋: v.SetDefault("V", "1.11") // 建立默認值
version: 99.99
config.go
package config
import (
"fmt"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
"os"
)
func LoadConfigFromYaml() (v *viper.Viper, err error) {
v = viper.New()
v.SetConfigName("config.yaml")
v.AddConfigPath("./config/")
v.SetConfigType("yaml")
v.Set("version", "2.22") // 顯示調用Set設置值
v.SetDefault("V", "1.11") // 建立默認值
// viper從環境變量讀取
v.SetEnvPrefix("spf")
v.BindEnv("id")
os.Setenv("spf_id", "111")
if err = v.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// Config file not found; ignore error if desired
fmt.Println("Config file not found; ignore error if desired")
} else {
// Config file was found but another error was produced
fmt.Println("Config file was found but another error was produced")
}
}
// 監控配置和重新獲取配置
v.WatchConfig()
v.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config file changed:", e.Name)
})
return v, err
}
main.go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"viperTest/config"
)
func main() {
router := gin.Default()
v, _ := config.LoadConfigFromYaml()
router.GET("/", func(context *gin.Context) {
context.JSON(200, gin.H{
"config": v.AllSettings(),
})
fmt.Println(v.GetString("db.password"), v.Get("id")) // 獲取單個配置屬性
})
router.Run("127.0.0.1:8899")
}
獲取值
在Viper中,根據值的類型,有幾種獲取值的方法。存在以下功能和方法:
Get(key string) : interface{}
GetBool(key string) : bool
GetFloat64(key string) : float64
GetInt(key string) : int
GetIntSlice(key string) : []int
GetString(key string) : string
GetStringMap(key string) : map[string]interface{}
GetStringMapString(key string) : map[string]string
GetStringSlice(key string) : []string
GetTime(key string) : time.Time
GetDuration(key string) : time.Duration
IsSet(key string) : bool
AllSettings() : map[string]interface{}
postman請求接口
{
"config": {
"db": {
"database": "docker01",
"host": "123.123.12.123",
"password": 123456,
"port": 33066,
"username": "mayanan"
},
"v": "1.11",
"version": "2.22"
}
}
此時把config.yaml中的內容改一下,再次請求接口,響應發生變化,根本不用重啟我們的應用程序,非常的友好
寫入配置文件
從配置文件中讀取配置文件是有用的,但是有時你想要存儲在運行時所做的所有修改。為此,可以使用下面一組命令,每個命令都有自己的用途:
WriteConfig - 將當前的viper配置寫入預定義的路徑並覆蓋(如果存在的話)。如果沒有預定義的路徑,則報錯。
SafeWriteConfig - 將當前的viper配置寫入預定義的路徑。如果沒有預定義的路徑,則報錯。如果存在,將不會覆蓋當前的配置文件。
WriteConfigAs - 將當前的viper配置寫入給定的文件路徑。將覆蓋給定的文件(如果它存在的話)。
SafeWriteConfigAs - 將當前的viper配置寫入給定的文件路徑。不會覆蓋給定的文件(如果它存在的話)。
根據經驗,標記為safe的所有方法都不會覆蓋任何文件,而是直接創建(如果不存在),而默認行為是創建或截斷。
小示例:
viper.WriteConfig() // 將當前配置寫入“viper.AddConfigPath()”和“viper.SetConfigName”設置的預定義路徑
viper.SafeWriteConfig()
viper.WriteConfigAs("/path/to/my/.config")
viper.SafeWriteConfigAs("/path/to/my/.config") // 因為該配置文件寫入過,所以會報錯
viper.SafeWriteConfigAs("/path/to/my/.other_config")
viper中使用環境變量
Viper 完全支持環境變量。這使得12因素的應用程序開箱即用。有五種方法可以幫助與 ENV 合作:
AutomaticEnv() // 可以通過v讀取:v.Get("id")
BindEnv(string...) : error // 綁定到viper中,既可以通過v讀取,也可以通過v拿到配置
SetEnvPrefix(string)
SetEnvKeyReplacer(string...) *strings.Replacer
AllowEmptyEnv(bool)
viper簡介
github.com/spf13/viper
viper配置文件映射到結構體
type ServerConfig struct {
ServiceName string `mapstructure:"name"`
Port int `mapstructure:"port"`
}
func main() {
v := viper.New()
//v.SetConfigName("config.yaml")
//v.SetConfigType("yaml")
//v.AddConfigPath("./")
// 文件的路徑如何設置
v.SetConfigFile("config.yaml") // 這一行跟上面三行功能實現相同
err := v.ReadInConfig()
if err != nil {
panic(err)
}
fmt.Println(v.GetString("name"))
// 將配置文件映射到結構體
var serverConfig ServerConfig
if err = v.Unmarshal(&serverConfig); err != nil {
panic("config unmarshal failed")
}
fmt.Println(serverConfig)
}
viper配置文件映射到嵌套結構體
點擊查看代碼
type MysqlConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
}
type ServerConfig struct {
ServiceName string `mapstructure:"name"`
MysqlInfo MysqlConfig `mapstructure:"mysql"`
}
func main() {
v := viper.New()
//v.SetConfigName("config.yaml")
//v.SetConfigType("yaml")
//v.AddConfigPath("./")
// 文件的路徑如何設置
v.SetConfigFile("config.yaml") // 這一行跟上面三行功能實現相同
err := v.ReadInConfig()
if err != nil {
panic(err)
}
fmt.Println(v.GetString("name"))
ret := v.Get("mysql").(map[string]interface{}) // 將接口類型轉換成map類型
fmt.Println(ret["host"], ret["port"])
// 將配置文件映射到結構體
var serverConfig ServerConfig
if err = v.Unmarshal(&serverConfig); err != nil {
panic("config unmarshal failed")
}
fmt.Println(serverConfig, serverConfig.ServiceName, serverConfig.MysqlInfo.Host, serverConfig.MysqlInfo.Port)
}
viper配置開發環境和生產環境隔離
viper動態監控配置文件的變化
點擊查看代碼
// 不用改任何代碼,而且線上和線下的代碼能隔離開
func GetEnvInfo(env string) bool {
viper.AutomaticEnv()
return viper.GetBool(env)
// 剛才設置的環境變量想要生效,我們必須得重啟所有goland
}
type MysqlConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
}
type ServerConfig struct {
ServiceName string `mapstructure:"name"`
MysqlInfo MysqlConfig `mapstructure:"mysql"`
}
func main() {
// 配置文件開發環境和生產環境隔離
debugMode := GetEnvInfo("MXSHOP_DEBUG")
var configFilePrefix = "config"
var configFileName = fmt.Sprintf("%s_pro.yaml", configFilePrefix)
if debugMode {
configFileName = fmt.Sprintf("%s_dev.yaml", configFilePrefix)
}
v := viper.New()
//v.SetConfigName("config_dev.yaml")
//v.SetConfigType("yaml")
//v.AddConfigPath("./")
// 文件的路徑如何設置
v.SetConfigFile(configFileName)
err := v.ReadInConfig()
if err != nil {
panic(err)
}
fmt.Println(v.GetString("name"))
ret := v.Get("mysql").(map[string]interface{}) // 將接口類型轉換成map類型
fmt.Println(ret["host"], ret["port"])
// 將配置文件映射到結構體
var serverConfig ServerConfig
if err = v.Unmarshal(&serverConfig); err != nil {
panic("config unmarshal failed")
}
fmt.Println(serverConfig, serverConfig.ServiceName, serverConfig.MysqlInfo.Host, serverConfig.MysqlInfo.Port)
// viper的功能,動態監控變化
v.WatchConfig()
v.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("config file changed", e.Name)
_ = v.ReadInConfig()
_ = v.Unmarshal(&serverConfig)
fmt.Println(serverConfig)
})
time.Sleep(time.Second * 300)
}