设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间14 现在时间14 缓存数据 十年生死两茫茫 不思量 自难忘

十年生死两茫茫 不思量 自难忘 -- 归去来兮

查看: 1121|回复: 3

详解go基于viper实现配置文件热更新及其源码分析

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:204
  • 打卡月天数:0
  • 打卡总奖励:3165
  • 最近打卡:2023-08-27 04:28:55
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
408
主题
383
精华
0
金钱
4390
积分
810
注册时间
2022-12-20
最后登录
2025-6-1

发表于 2024-3-12 13:34:52 | 显示全部楼层 |阅读模式
go第三方库 github.com/spf13/viper  实现了对配置文件的读取并注入到结构中,好用方便。
其中以
  1. viperInstance := viper.New()        // viper实例
  2. viperInstance.WatchConfig()
  3. viperInstance.OnConfigChange(func(e fsnotify.Event) {
  4.         log.Print("Config file updated.")
  5.         viperLoadConf(viperInstance)  // 加载配置的方法
  6. })
复制代码
可实现配置的热更新,不用重启项目新配置即可生效(实现热加载的方法也不止这一种,比如以文件的上次修改时间来判断等)。
为什么这么写?这样写为什么就能立即生效?基于这两个问题一起来看看viper是怎样实现热更新的。
上面代码的核心一共两处:WatchConfig()方法、OnConfigChange()方法。WatchConfig()方法用来开启事件监听,确定用户操作文件后该文件是否可正常读取,并将内容注入到viper实例的config字段,先来看看WatchConfig()方法:
  1. func (v *Viper) WatchConfig() {
  2.         go func() {
  3.       // 建立新的监视处理程序,开启一个协程开始等待事件
  4.       // 从I/O完成端口读取,将事件注入到Event对象中:Watcher.Events
  5.                 watcher, err := fsnotify.NewWatcher()  
  6.                 if err != nil {
  7.                         log.Fatal(err)
  8.                 }
  9.                 defer watcher.Close()

  10.                 // we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way
  11.                 filename, err := v.getConfigFile()  
  12.                 if err != nil {
  13.                         log.Println("error:", err)
  14.                         return
  15.                 }

  16.                 configFile := filepath.Clean(filename)    //配置文件E:\etc\bizsvc\config.yml
  17.                 configDir, _ := filepath.Split(configFile)  // E:\etc\bizsvc\

  18.                 done := make(chan bool)
  19.                 go func() {
  20.                         for {
  21.                                 select {
  22.         // 读取的event对象有两个属性,Name为E:\etc\bizsvc\config.yml,Op为write(对文件的操作)
  23.                                 case event := <-watcher.Events:
  24.                 // 清除内部的..和他前面的元素,清除当前路径.,用来判断操作的文件是否是configFile
  25.                                         if filepath.Clean(event.Name) == configFile {
  26.         // 如果对该文件进行了创建操作或写操作
  27.                                                 if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create {
  28.                                                         err := v.ReadInConfig()
  29.                                                         if err != nil {
  30.                                                                 log.Println("error:", err)
  31.                                                         }
  32.                                                         v.onConfigChange(event)
  33.                                                 }
  34.                                         }
  35.                                 case err := <-watcher.Errors:
  36.          // 有错误将打印
  37.                                         log.Println("error:", err)
  38.                                 }
  39.                         }
  40.                 }()

  41.                 watcher.Add(configDir)
  42.                 <-done
  43.         }()
  44. }
复制代码
其中,fsnotify是用来监控目录及文件的第三方库;  watcher, err := fsnotify.NewWatcher() 用来建立新的监视处理程序,它会开启一个协程开始等待读取事件,完成 从I / O完成端口读取任务,将事件注入到Event对象中,即Watcher.Events;
1.png

执行v.ReadInConfig()后配置文件的内容将重新读取到viper实例中,如下图:

2.png

执行完v.ReadInConfig()后,config字段的内容已经是用户修改的最新内容了;
其中这行v.onConfigChange(event)的onConfigChange是核心结构体Viper的一个属性,类型是func:
  1. type Viper struct {
  2.         // Delimiter that separates a list of keys
  3.         // used to access a nested value in one go
  4.         keyDelim string

  5.         // A set of paths to look for the config file in
  6.         configPaths []string

  7.         // The filesystem to read config from.
  8.         fs afero.Fs

  9.         // A set of remote providers to search for the configuration
  10.         remoteProviders []*defaultRemoteProvider

  11.         // Name of file to look for inside the path
  12.         configName string
  13.         configFile string
  14.         configType string
  15.         envPrefix string

  16.         automaticEnvApplied bool
  17.         envKeyReplacer   *strings.Replacer

  18.         config     map[string]interface{}
  19.         override    map[string]interface{}
  20.         defaults    map[string]interface{}
  21.         kvstore    map[string]interface{}
  22.         pflags     map[string]FlagValue
  23.         env      map[string]string
  24.         aliases    map[string]string
  25.         typeByDefValue bool

  26.         // Store read properties on the object so that we can write back in order with comments.
  27.         // This will only be used if the configuration read is a properties file.
  28.         properties *properties.Properties

  29.         onConfigChange func(fsnotify.Event)
  30. }
复制代码
它用来传入本次event来执行你写的函数。为什么修改会立即生效?相信第二个疑问已经得到解决了。
接下来看看OnConfigChange(func(e fsnotify.Event) {...... })的运行情况:
  1. func (v *Viper) OnConfigChange(run func(in fsnotify.Event)) {
  2.         v.onConfigChange = run
  3. }
复制代码
方法参数为一个函数,类型为func(in fsnotify.Event)) {},这就意味着开发者需要把你自己的执行逻辑放到这个func里面,在监听到event时就会执行你写的函数,所以就可以这样写:
  1.         viperInstance.OnConfigChange(func(e fsnotify.Event) {
  2.                 log.Print("Config file updated.")
  3.                 viperLoadConf(viperInstance)  // viperLoadConf函数就是将最新配置注入到自定义结构体对象的逻辑
  4.         })
复制代码
而OnConfigChange方法的参数会赋值给形参run并传到viper实例的onConfigChange属性,以WatchConfig()方法中的v.onConfigChange(event)来执行这个函数。
到此,第一个疑问也就解决了。
到此这篇关于详解go基于viper实现配置文件热更新及其源码分析的文章就介绍到这了,更多相关go viper文件热更新内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
21
积分
22
注册时间
2022-12-25
最后登录
2022-12-25

发表于 2024-3-18 15:11:22 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
17
积分
14
注册时间
2022-12-25
最后登录
2022-12-25

发表于 2025-3-16 16:35:21 | 显示全部楼层
顶顶更健康!!!
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
17
积分
14
注册时间
2022-12-27
最后登录
2022-12-27

发表于 2025-4-18 21:36:46 | 显示全部楼层
感谢楼主,顶。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼
4楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表