使用Go进行系统开发时Viper的使用

Viper的使用

在学习如何使用viper之前,我们需要先了解一些关于配置的相关概念。

来源

从配置的来源上进行分类,我们一般可以分为:

  • 启动参数:某一次运行时需要的参数,可以考虑在这里提供。最常见的就是命令行工具的使用,会要求我们传入各种参数。
  • 环境变量:和具体的实例有关的参数都放在这里。比如说,实例的权重,实例的分组信息等。
  • 配置文件:一些当下环境中所需要的通用的配置。比如常用的数据库连接信息等。
  • 远程配置中心:它和配置文件可以说是相互补充的,除了启动程序所需的最少配置,剩下的配置都可以放在远程配置中心。

来源的优先级:所谓的优先级,是指如果不同来源都有同一个配置项,那么究竟该用哪个值呢?

我先谈谈我常用的实践:

  1. 命令行最权威,因为是我主动在启动的时候输入的,所以一切配置中,它的优先级别最高。
  2. 环境变量次之,因为这是我自己电脑中设置的环境变量,所以它的优先级也比较高。
  3. 配置文件再次之,因为配置文件可能是同事写的,我只是通过Git将其同步下来而已。
  4. 远程配置中心优先级最低。

远程配置中心的两次加载:

  • 第一次加载最基本的配置,包括:
    • 远程配置的连接信息,二次加载的时候需要先连上配置中心。
    • 日志相关配置,确保日志模块初始化成功,后续可以输出日志。
  • 第二次则是完全加载:
    • 读取系统所需的全部依赖,并且用于初始化各种第三方。例如,连接数据库。
    • 如果在第一次加载中的配置,在远程配置中心里面也能找到,那么就会被覆盖掉,并且再次初始化使用这些配置的组建。比如说,再次初始化日志组件,连上日志分析平台等。

读取本地配置

安装viper

go get github.com/spf13/viper

初始化

使用viper进行初始化,有两种方式。
一种是SetConfigName

func InitViper() {
	//读取的文件名字是 dev
	viper.SetConfigName("dev")
	//读取的文件类型为 yaml
	viper.SetConfigType("yaml")
	//当前工作目录下的 config 文件夹
	viper.AddConfigPath("config")
	err := viper.ReadInConfig()
	if err != nil {
		panic(err)
	}
}

一种是使用SetConfigFile

func InitViperV1() {
	viper.SetConfigFile("config/dev.yaml")
	err := viper.ReadInConfig()
	if err != nil {
		panic(err)
	}
}

如果这里出现了无法读取配置文件。记住,viper里面是从Go中的working directory开始定位的。

读取配置

当我们需要初始化某个功能的时候,我们就可以直接读取一个特定的配置项。

比如,我读取 redis 配置项。

func InitRedis() redis.Cmdable {
	// 我们需要一个 redis 的客户端
	cmd := redis.NewClient(&redis.Options{
		// 使用 GetString 方法获取配置文件中的 redis 地址
		Addr : viper.GetString("redis.addr"),
	})
	return cmd
}

配置文件中的配置。

redis:
  addr: "localhost:6379"

一般,不太建议这样写。一般都是这么建议的,相关的配置都定义到一个结构体里面,然后直接初始化整个结构体就行啦。

下面是我推荐的写法。

func InitDB() *gorm.DB {
	type Config struct {
		DSN string `yaml:"dsn"`
	}
	var c Config
	err := viper.UnmarshalKey("db", &c)
	if err != nil {
		panic("db config error")
	}
	db, err := gorm.Open(mysql.Open(c.DSN), &gorm.Config{})
	if err != nil {
		panic("db connect error")
	}
	return db
}

在初始化的时候,我们首先定义一个内部的结构体,用来接收全部相关的配置。(除非别的地方也要用到这个结构体,不然就保持内部定义结构体)。

设置默认值

在有时候,我们没有使用动态的配置项,而是使用了我们默认的配置。该如何实现呢?

这里有两种实现方式:

  • 一种是使用viper中的SetDefault方法。
func InitViperV1() {
	// 设置 db.dsn 默认值
	viper.SetDefault("db.dsn", "root:123456@tcp(127.0.0.1:3306)/we_book?charset=utf8mb4&parseTime=True&loc=Local")
	viper.SetConfigFile("config/dev.yaml")
	err := viper.ReadInConfig()
	if err != nil {
		panic(err)
	}
}
  • 一种是利用好结构体,再调用UnmarshalKey之前,设置好默认值。如果配置里面没有对应的配置项,那么最终结果就是使用默认值。
func InitDB() *gorm.DB {
	type Config struct {
		DSN string `yaml:"dsn"`
	}
	
	// 在结构体中使用默认的 dsn
	c := Config{
		DSN: "root:123456789@tcp(127.0.0.1:3306)/we_book?charset=utf8mb4&parseTime=True&loc=Local",
	}
	
	...
}

这里,我更倾向于用第二种,因为可以把默认值放到业务对应的地方。

直接读取

如果我们想要直接读取,可以使用ReadConfig,这个方法允许传入一个io.Reader

func InitViperV2() {
	cfg := `
		db:
		  dsn: "root:123456789@tcp(127.0.0.1:3306)/we_book?charset=utf8mb4&parseTime=True&loc=Local"
		
		redis:
		  addr: "localhost:6379"
		`
	viper.SetConfigType("yaml")
	err := viper.ReadConfig(bytes.NewReader([]byte(cfg)))
	if err != nil {
		panic("read config error")
	}
}

以上就是关于viper的简单使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值