Viper:强大的Go配置解析库

1 介绍

Viper是适用于Go应用程序的完整配置解决方案。它被设计用于在应用程序中工作,并且可以处理所有类型的配置需求和格式。目前Star 26.6k, 它支持以下特性:

  • 设置默认值
  • 从JSON、TOML、YAML、HCL、envfile和Java properties格式的配置文件读取配置信息
  • 实时监控和重新读取配置文件(可选)
  • 从环境变量中读取
  • 从远程配置系统(etcd或Consul)读取并监控配置变化
  • 从命令行参数读取配置
  • 从buffer读取配置
  • 显式配置值

2 Golang项目中的使用

2.1 在go中安装Viper

BASH 复制代码
# 终端中输入如下命令
ArchitePlus@MacBook-Air traffic.demo % go get github.com/spf13/viper

2.2 编写通用配置文件

因为能支持多重配置文件格式,包含 JSON、TOML、YAML、HCL、INI、envfile 和 Java 属性文件,方便开发者根据项目需求选择合适的格式。

我们这边使用yaml做示例。

创建一个conf文件夹,添加子文件夹files,然后在下面添加config.yaml,里面可以放一些基本的、通用的配置信息。

YAML 复制代码
app: # 应用基本配置
  env: local # 环境名称
  port: 8888 # 服务监听端口号
  app_name: traffic-demo # 应用名称
  app_url: http://localhost # 应用访问地址


MySQL: # MySQL配置
  host: 127.0.0.1 # MySQL主机地址
  port: 3306 # MySQL端口号
  user: root # MySQL用户名
  password: <PASSWORD> 
  db_name: traffic # MySQL数据库名

可以看到,我们有两个配置信息,一个是 app,一个是MySQL。

2.3 编写用户自定义配置文件

还有一些用户自定义的配置文件(可能有多个), 是需要根据不同的运行环境(local、dev、beta、prod)来进行区分的.所以我们在config/files/下面创建四个文件夹 localdevbetaprod 四个文件夹,每个文件夹都有一个custom.yaml文件,当 app.env 的值变化的时候,读取的文件也跟着变化,下面是local的信息

YAML 复制代码
white_list: 
  user_id: # 用户列表
  - 063105015
  - 063105024
  - 063105028
  request_path: # 访问路径
  - /api/v1/users
  - /api/v1/ops

2.4 配置映射的结构体

我们需要配置结构体(实体对象)来映射这俩配置,这样的话,后面在调用的时候非常方便。

conf文件夹下面添加子文件夹model,存放解析映射的结构体,这边新增一个config.go和一个custom.go文件,内容如下:

2.4.1 config.go

GO 复制代码
package config

// 配置文件解析汇总
type Configuration struct {
	App   App   `mapstructure:"app" json:"app" yaml:"app"`
	MYSQL MYSQL `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
}

// 配置文件解析:app
type App struct {
	Env     string `mapstructure:"env" json:"env" yaml:"env"`
	Port    string `mapstructure:"port" json:"port" yaml:"port"`
	AppName string `mapstructure:"app_name" json:"app_name" yaml:"app_name"`
	AppUrl  string `mapstructure:"app_url" json:"app_url" yaml:"app_url"`
}

// 配置文件解析:mysql
type MYSQL struct {
	Host     string `mapstructure:"host" json:"host" yaml:"host"`
	Port     string `mapstructure:"poet" json:"port" yaml:"port"`
	User     string `mapstructure:"user" json:"user" yaml:"user"`
	Password string `mapstructure:"password" json:"password" yaml:"password"`
	DbName   string `mapstructure:"db_name" json:"db_name" yaml:"db_name"`
}

2.4.2 custom.go

GO 复制代码
package config

type Custom struct {
	WhiteList whiteList `mapstructure:"white_list" json:"white_list" yaml:"white_list"`
}

// 配置文件解析汇总
type whiteList struct {
	UserId      []string `mapstructure:"user_id" json:"user_id" yaml:"user_id"`
	RequestPath []string `mapstructure:"request_path" json:"request_path" yaml:"request_path"`
}

2.5 创建Global全局变量解析

新建一个 global/app.go 文件,定义 Application 结构体,用来存放一些项目启动时的变量,方便调用。

目前先将 viper 结构体和 Configuration 结构体放入,后续会陆续添加其他配置信息。

GO 复制代码
package global

import (
	"github.com/spf13/viper"
	config "traffic.demo/config/model"
)

// 定义一个全局的Application
type Application struct {
	ConfigViper *viper.Viper
	Config      config.Configuration
	Custom      config.Custom
}

// 初始化Application
var App = new(Application)

2.5 关键步骤:结构体映射逻辑

配置文件要映射到结构体,这样才能把配置数据提取出来,这边创建 bootstrap/config.go 文件,作为核心解析代码的载体,代码如下(代码中的解释已经很清楚了):

GO 复制代码
package bootstrap

import (
	"fmt"

	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
	"traffic.demo/global"
)

// configAssemble 是一个泛型函数,用于组装配置文件并返回 viper.Viper 指针
//
// 参数:
//
//	configPath string - 配置文件路径
//	viperStruct T - 用来接收配置文件的结构体
//
// 返回值:
//
//	*viper.Viper - viper.Viper 指针
func configAssemble[T any](configPath string, viperStruct T) *viper.Viper {
	// 初始化 viper
	v := viper.New()
	// 配置文件地址
	v.SetConfigFile(configPath)
	// 配置文件类型,yaml
	v.SetConfigType("yaml")
	if err := v.ReadInConfig(); err != nil {
		panic(fmt.Errorf("read config failed: %s \n", err))
	}

	// 监听配置文件
	v.WatchConfig()
	v.OnConfigChange(func(in fsnotify.Event) {
		fmt.Println("config file changed:", in.Name)
		// 重载配置 &global.App.Config
		if err := v.Unmarshal(viperStruct); err != nil {
			fmt.Println(err)
		}
	})
	// 将配置赋值给全局变量 &global.App.Config
	if err := v.Unmarshal(viperStruct); err != nil {
		fmt.Println(err)
	}

	return v
}

// InitializeConfig 初始化配置函数
func InitializeConfig() {
	// 全局应用文件配置路径,这边是我们的具体global config文件地址
	config := "conf/files/config.yaml"
	configAssemble(config, &global.App.Config)

	// 用户自定义的配置(根据不同的运行环境,加载不同的配置文件)
	customConfig := fmt.Sprintf("%s%s%s", "conf/files/", global.App.Config.App.Env, "/custom.yaml")
	configAssemble(customConfig, &global.App.Custom)

}

2.6 整体文件结构如下

2.7 运行结果

main.go 代码如下:

GO 复制代码
package main

import (
	"fmt"
	"traffic.demo/global"
)

// main 函数是程序的入口点
func main() {

    bootstrap.InitializeConfig()
    fmt.Println("Traffic Service Started...!")

	var globalCong = global.App.Config
	fmt.Printf("globalCong: %+v\n", globalCong)
	var customCong = global.App.Custom
	fmt.Printf("customCong: %+v\n", customCong)
}

效果如下:

3 总结

Viper 是一个功能强大、简洁、易于的 Go 配置库,帮助开发者轻松管理应用程序的配置,并提供灵活的接入方式

相关推荐
lead520lyq3 小时前
Golang本地内存缓存
开发语言·缓存·golang
小邓吖4 小时前
自己做了一个工具网站
前端·分布式·后端·中间件·架构·golang
金庆12 小时前
Commit Hash from debug.ReadBuildInfo()
golang
源代码•宸13 小时前
Golang面试题库(sync.Map)
开发语言·后端·面试·golang·map·sync.map·expunged
终生成长者13 小时前
Golang cursorrule
开发语言·后端·golang
席万里13 小时前
基于Go和Vue快速开发的博客系统-快速上手Gin框架
vue.js·golang·gin
源代码•宸14 小时前
Golang面试题库(Map)
后端·面试·golang·map·bmap·hmap·nevacuate
只是懒得想了15 小时前
用Go通道实现并发安全队列:从基础到最佳实践
开发语言·数据库·golang·go·并发安全
Fgaoxing1 天前
Go反射:性能瓶颈与零拷贝优化
性能优化·golang·反射
源代码•宸1 天前
Leetcode—94. 二叉树的中序遍历【简单】
经验分享·后端·算法·leetcode·职场和发展·golang·dfs