GoLang实现Viper库的封装流程详解

 更新时间:2023年05月19日 08:38:18   作者:三杯温开水  
Viper是一个用于Go语言应用程序的配置管理库,它提供了一种简单而灵活的方式来处理应用程序的配置,支持多种格式的配置文件,这篇文章主要介绍了GoLang封装Viper库的流程,感兴趣的同学可以参考下文

Viper是什么

Viper是一个用于Go语言应用程序的配置管理库。它提供了一种简单而灵活的方式来处理应用程序的配置,支持多种格式的配置文件,并提供了一组API来读取和使用这些配置。

Viper支持多种配置文件格式,包括JSON、TOML、YAML和HCL等。它还支持环境变量和命令行标志等配置方式。这使得Viper非常适合需要在不同环境中运行(如开发、测试和生产环境)的应用程序,因为可以使用不同的配置文件和设置来管理应用程序的行为。 优点:使用Viper,可以轻松地将配置信息加载到应用程序中,并在需要时获取这些信息。Viper还提供了一些方便的功能,例如默认值、类型转换和键名重映射等,使得配置管理变得更加简单和灵活。

实现Viper的封装

在根目录下创建一个core文件,然后在core文件中创建多一个interal文件,这个interal文件的方法仅能让core里进行调用的,一般可以将一些仅给core内方法使用并且是需要封装的方法放置在内(调取internal包中的方法不需要添加core包名 )。如图大概就是这样的,然后就是定义一个viper的interface,实现内部的GetFileGetFiles两个方法,前者是配置信息,后者是文件夹路径。当然我们也可以使用embed这样方式实现,但是最好本地也实现一个比较稳妥一点!

interal文件夹代码实现

core/interal/viper_interface.go

type IViper interface {
	// GetFile 获取文件信息
	GetFile(path, filename string) io.Reader
	// GetFiles 获取配置文件夹信息
	GetFiles(dir string) ([]fs.DirEntry, error)
}

core/interal/viper.go

var Viper = new(viper)
type viper struct{}
func (v *viper) GetFile(path, filename string) io.Reader {
	file, err := os.Open(filepath.Join(path, filename))
	if err != nil {
		return nil
	}
	defer func() {
		_ = file.Close()
	}()
	all, err := io.ReadAll(file)
	if err != nil {
		return nil
	}
	return bytes.NewReader(all)
}
func (v *viper) GetFiles(dir string) ([]os.DirEntry, error) {
	entries, err := os.ReadDir(dir)
	if err != nil {
		return nil, errors.Wrapf(err, "[viper][path:%s]获取配置文件夹信息失败!", dir)
	}
	return entries, nil
}

core/interal/vuper_embed.go (实现本地embed标记,当然推荐使用下面本地实现的方法)

var Viper = new(viper)
type viper struct{}
func (v *viper) GetFile(path, filename string) io.Reader {
	file, err := global.Configs.Open(filepath.Join(path, filename))
	if err != nil {
		fmt.Printf("[viper][path:%s][filename:%s]文件不存在!\n", path, filename)
		return nil
	}
	return file
}
func (v *viper) GetFiles(dir string) ([]fs.DirEntry, error) {
	entries, err := global.Configs.ReadDir(dir)
	if err != nil {
		return nil, errors.Wrapf(err, "[viper][embed][dir:%s]获取配置文件夹信息失败!", dir)
	}
	return entries, nil
}

core/viper.go

我这里的config文件夹中的配置yaml格式如:gorm.debug.yaml

var Viper = new(_viper)
type _viper struct{}
// Initialization .
// 优先级: 命令行 > 环境变量 > 默认值
func (c *_viper) Initialization(path ...string) {
	var configs string
	if len(path) == 0 {
		flag.StringVar(&configs, "c", "", "choose configs dir.")
		flag.Parse()
		if configs == "" {
			env := os.Getenv(internal.ConfigsEnv)
			if env == "" { // 判断 internal.ConfigEnv 常量存储的环境变量是否为空
				configs = internal.ConfigsPath
				fmt.Printf("您正在使用配置默认文件夹:%s,configs的文件夹路径为%s\n", internal.ConfigsPath, configs)
			} else {
				configs = env
				fmt.Printf("您正在使用%s环境变量,configs的文件夹路径为%s\n", internal.ConfigsEnv, configs)
			}
		} else { // 命令行参数不为空 将值赋值于configs
			fmt.Printf("您正在使用命令行的-c参数传递的值,configs的文件夹路径为%s\n", configs)
		}
	} else { // path 这个切片大于0,取第一个值赋值到configs
		configs = path[0]
	}
	v := viper.New()
	v.AddConfigPath(configs)
	entries, err := internal.Viper.GetFiles(configs)
	if err != nil {
		fmt.Printf("%+v\n", err)
		return
	}
	for i := 0; i < len(entries); i++ {
		if entries[i].IsDir() { // 忽略配置文件夹里的文件夹
			continue
		}
		filename := entries[i].Name()
		// 分割文件名
		names := strings.Split(filename, ".")
		if len(names) == 3 {
			config := names[0] // 文件名
			mode := names[1] // 模式
			yaml := names[2] // 文件后缀
			if mode != gin.Mode() {
				continue
			}
			// 拼接
			v.SetConfigName(strings.Join([]string{config, mode}, "."))
			v.SetConfigType(yaml)
			reader := internal.Viper.GetFile(configs, filename)
			err = v.MergeConfig(reader)
			if err != nil {
				fmt.Printf("[viper][filename:%s][err:%v]配置文件读取失败!\n", filename, err)
				return
			}
			// 读取配置文件
			err = v.ReadInConfig()
			if err != nil {
				fmt.Printf("[viper][filename:%s][err:%v]配置文件读取失败!\n", filename, err)
				continue
			}
			// 反序列化config
			err = v.Unmarshal(&global.Config)
			if err != nil {
				fmt.Printf("[viper][err:%v]反序列化失败!\n", err)
				continue
			}
			v.OnConfigChange(func(in fsnotify.Event) {
				fmt.Printf("[viper][filename:%s]配置文件更新\n", in.Name)
				err = v.Unmarshal(&global.Config)
				if err != nil {
					fmt.Printf("[viper][err:%v]反序列化失败!\n", err)
				}
			})
			v.WatchConfig()
		}
	}
	// 注册到全局
	global.Viper = v
}

根目录下创建embed.go

如果在自己练习的时候已在编辑器中配置了这个embed标记可以忽略上述本地的viper_embed.go文件(如下图配置所示),但是建议不忽略上述的viper_embed.go文件

package main
// 这些有import导报
// import (......)
func init() {
	global.Configs = configs
}
var (
	//go:embed configs
	configs embed.FS
)

global中引入结构体

global/global.go

var (
	Viper  *viper.Viper
)

到此这篇关于GoLang实现Viper库的封装流程详解的文章就介绍到这了,更多相关GoLang Viper库封装内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • go中new和make的区别小结

    go中new和make的区别小结

    new 只分配内存,make 用于初始化 slice、map 和 channel,本文详细的介绍了go中new和make的区别小结,感兴趣的可以了解一下
    2023-05-05
  • golang实现循环队列的示例代码

    golang实现循环队列的示例代码

    循环队列是一种使用固定大小的数组来实现队列的数据结构,本文主要介绍了golang实现循环队列的示例代码,具有一定的参考价值,感兴趣的可以了解一下
    2024-07-07
  • Golang中interface的基本用法详解

    Golang中interface的基本用法详解

    Go 中接口也是一个使用得非常频繁的特性,好的软件设计往往离不开接口的使用,比如依赖倒置原则(通过抽象出接口,分离了具体实现与实际使用的耦合)。 今天,就让我们来了解一下 Go 中接口的一些基本用法
    2023-01-01
  • 一文详解Golang中的匿名变量

    一文详解Golang中的匿名变量

    匿名变量是一种特殊类型的变量,可以简化代码并提高可读性,本文将为大家详细介绍一下golang中匿名变量的定义、特性和使用方法,需要的可以参考下
    2023-09-09
  • Go语言程序开发gRPC服务

    Go语言程序开发gRPC服务

    这篇文章主要为大家介绍了Go语言程序开发gRPC服务,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • golang使用grpc+go-kit模拟oauth认证的操作

    golang使用grpc+go-kit模拟oauth认证的操作

    这篇文章主要介绍了golang使用grpc+go-kit模拟oauth认证的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • Golang Cron 定时任务的实现示例

    Golang Cron 定时任务的实现示例

    这篇文章主要介绍了Golang Cron 定时任务的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • go语言中的Stringer的使用示例详解

    go语言中的Stringer的使用示例详解

    Go 语言中的 Stringer 是一个非常有用的接口,它在标准库的 fmt 包中定义,Stringer 接口允许类型定义它们的字符串表示方式,这在格式化输出时特别有用,这篇文章主要介绍了go语言中的Stringer的使用,需要的朋友可以参考下
    2025-02-02
  • Golang中对json的优雅处理方式

    Golang中对json的优雅处理方式

    这篇文章主要给大家介绍了关于Golang中对json的优雅处理方式,解析JSON在golang中很麻烦,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-06-06
  • Go语言通过TCP协议实现聊天室功能

    Go语言通过TCP协议实现聊天室功能

    这篇文章主要为大家详细介绍了Go语言中如何通过TCP协议实现聊天室功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-04-04

最新评论