go viper OnConfigChange 调用多次的解决方案

viper 是一个读取配置文件的库,支持多种格式,方便快捷,把文件读成可以解析的map方式.

一般把json,yaml转成go的结构体进行使用.

OnConfigChange这个函数是监听文件已经被修改了,就会进行执行这个函数.而作者的实现方式,可能是监听这个文件写入状态吧,每保存一次,就会调用一次这个函数.和我们的想法是不同的.

而且在别的文本编辑器中进行保存,可能会调用多次,我修改了一次,而执行了多次这个函数,这是不能够忍受的.

什么是配置文件修改? 最恰当的是修改了配置文件的元素.目前库是不支持这种的.而我们也没有必要对其要求过高.

如果一个文件没有发生改变,只是保存,你执行了这个函数是不对的.而解决方案之一是把配置文件进行md5一下,保存其md5值,在调用这个函数时,再次读取文件进行md5.两者比对,如果相等就不执行下面的逻辑.

这样就解决了,一模一样的配置文件,保存多次,不会执行后续的逻辑.

但是呢,杜绝了大部分的场景,比如修改了一次,保存了两次,依旧会有看起来一模一样的配置,md5值不同.但也无所谓.咱们可以如下面的说明,对每个配置进行比对.

如果仅仅是换行,或者修改了部分的配置,大家可以对其结构体转成json,再md5值,改变前和改变后的.如果值不同,就执行后续逻辑.道理是相通的.

部分参考代码

yaml
server:
  port: '36501'
  heartbeat: 12 #  

package main

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/mitchellh/mapstructure"
	"github.com/spf13/viper"
)

var confMD5 string
func GetMD5(s []byte) string {
	m := md5.New()
	m.Write([]byte(s))
	return hex.EncodeToString(m.Sum(nil))
}

func ReadFileMd5(sfile string) (string, error) {
	ssconfig, err := ioutil.ReadFile(sfile )
	if err != nil {
		return "", err
	}
	return GetMD5(ssconfig), nil
}
type ConfigServer struct {
	Server       Server         `mapstructure:"server" json:"server"`
}
func (c *ConfigServer) MD5String() string {
	jsonBytes, err := json.Marshal(c)
	if err != nil {
		return ""
	}
	return ulits.GetMD5(jsonBytes)
}
func 
readcfg(){
	var err error
	confMD5, err = ReadFileMd5("config.yaml")
	fmt.Printf("[%+v]\n", confMD5)

	v := viper.New()
	v.SetConfigFile("config.yaml")
	err = v.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}
  v.WatchConfig()
allvalue := v.AllSettings()
	fmt.Printf("\n\nkey [%+v]\n", allvalue)// 是所有的值
		v.OnConfigChange(func(e fsnotify.Event) {

		tconfMD5, _ := ReadFileMd5("config.yaml")
		fmt.Printf("[%+v]\n", tconfMD5)
		if tconfMD5 == confMD5 {
			return
		}
		// 这说明文件发生了改变.
		confMD5 = tconfMD5
		fmt.Println("cfg start....", e.String(), e.Name)
	
	//  定义一个接收的结构体
		var ttmpcfg config.ConfigServer
		// 对其结构体md5 ,这是默认的空的结构体md5值
		nilMD5 := ttmpcfg.MD5String() 
		// 然后把配置读取到结构体当中
		if err := v.Unmarshal(&ttmpcfg); err != nil {
			return
		}
       // 注意判断当前的结构体是空的,因为程序有可能会走多次.没有读取出内容来是不对的,所以需要与空结构体json md5
		if nilMD5 == ttmpcfg.MD5String() {
			return
		}
}
func main() {
	readcfg()
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值