go-viper实践

一、需求

1. 本地开发读取yaml中的配置,并序列化成对象

2. 支持线上环境配置env

3. 本地环境和线上环境无缝衔接不需要修改代码

二、viper实践

1. viper文档

viper文档

2. 配置本地yaml

settings:
  application:
    # dev开发环境 test测试环境 prod线上环境
    mode: dev
    # 服务器ip,默认使用 0.0.0.0
    host: 0.0.0.0
    # 服务名称
    name:  DemoApp
    # 服务端口号
    port: 8000 
    # 读超时(s)
    readtimeout: 10
    # 写超时(s)
    writertimeout: 2
    # 数据权限功能开关
    enabledp: false

3. 封装config对象,并加载配置

代码如下(示例):

package config

import (
	"fmt"
	"github.com/spf13/viper"
	"strings"
)

var ApplicationConfig = new(Application)

type Application struct {
	ReadTimeout   int
	WriterTimeout int
	Host          string
	Port          int64
	Name          string
	Mode          string
	DemoMsg       string
}

// Config 配置集合
type Config struct {
	Application *Application `yaml:"application"`
}

type Settings struct {
	Settings Config `yaml:"settings"`
}

var _cfg *Settings

// Setup 载入配置文件
func Setup(configFile string, fs ...func()) {
_cfg = &Settings{
		Settings: Config{
			Application: ApplicationConfig,
		},
	}

	v := viper.New()
	//自动获取全部的env加入到viper中。(如果环境变量多就全部加进来)默认别名和环境变量名一致
	v.AutomaticEnv()

	//将加入的环境变量*_*_格式替换成 *.*格式
	//(因为从环境变量读是按"a.b.c.d"的格式读取,所以要给在viper维护一个别名对象,给环境变量一个别名)
	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

	// 配置文件位置
	v.SetConfigFile(configFile)

	//支持 "yaml", "yml", "json", "toml", "hcl", "tfvars", "ini", "properties", "props", "prop", "dotenv", "env":
	v.SetConfigType("yaml")

	//读文件到viper配置中
	err := v.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}

	// 系列化成config对象
	if err := v.Unmarshal(&_cfg); err != nil {
		fmt.Println(err)
	}

	fmt.Println("所有的key: ")
	for _,k := range v.AllKeys(){
		fmt.Println(k)
	}
	fmt.Println("所有的config: \n",v.AllSettings())

}

4. 单元测试

代码如下(示例):

import (
	"encoding/json"
	"fmt"
	"github.com/spf13/viper"
	"os"
	"strings"
	"testing"
)

func init() {
	os.Setenv("SETTINGS_APPLICATION_MODE","test")
	os.Setenv("SETTINGS_APPLICATION_HOST","127.0.0.10")
	os.Setenv("SETTINGS_APPLICATION_NAME","APP")
	os.Setenv("SETTINGS_APPLICATION_PORT","9001")
	os.Setenv("SETTINGS_APPLICATION_READTIMEOUT","1")
	os.Setenv("SETTINGS_APPLICATION_ENABLEDP","true")
}

func TestSetup(t *testing.T)  {
	Setup("app_settings.yaml")
	marshal, err := json.Marshal(_cfg)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("序列化config: \n",string(marshal))
}

执行结果:

=== RUN   TestSetup
所有的key: 
settings.application.enabledp
settings.application.mode
settings.application.host
settings.application.name
settings.application.port
settings.application.readtimeout
settings.application.writertimeout
所有的config: 
 map[settings:map[application:map[enabledp:true host:127.0.0.10 mode:test name:APP port:9001 readtimeout:1 writertimeout:2]]]
序列化config: 
 {"Settings":{"Application":{"ReadTimeout":1,"WriterTimeout":2,"Host":"127.0.0.10","Port":9001,"Name":"APP","Mode":"test","DemoMsg":""}}}
--- PASS: TestViperSettings (0.00s)
PASS

总结

通过实践,viper能够满足本地环境和线上环境的无缝切换,自动识别环境变量。

1. yaml + env 思路

  1. 从yaml中读取配置,主要是为了序列化出要用到的参数。
  2. 使用v.AutomaticEnv(),自动加载出环境变量到viper。
  3. 将环境变量替换成掉yaml中读取的值。(注意:LoopEnv 环境变量如果存在就返回,如果不存在则用下一个优先级的值。)

2. viper配置读取的优先级

  1. Viper将首先检查别名是否存在。
  2. 然后按默认读取优先级别检查:flag > env > config file, key/value store.
  3. 最后,如果没有找到值并且flagDefault为true,并且键对应于一个标志,则返回标志的默认值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值