package conf import ( "encoding/json" "errors" "leafstalk/log" "reflect" "sync" "leafstalk/otherutils/deepcopy" ) // EventFunc 动态配置事件回调函数类型定义 type EventFunc func(key string, val interface{}) // event 动态事件结构体 type event struct { sync.Mutex config map[string]interface{} // 本地缓存配置。用于初始化和对比新配置中的差异项,当存在差异项时进行回调处理使用 list map[string][]EventFunc // 所有事件的列表 } var dynamicEvent *event // 动态事件实例 // initDynamicEvent 初始化动态配置事件 func initDynamicEvent(cfgCenter *ConfigCenterAgent, group string) (err error) { dynamicEvent = &event{ list: make(map[string][]EventFunc), } // 初始化时先获取一次动态配置,将其保存到本地 content, err := cfgCenter.GetConfig("dynamicConfig", group) if err != nil { return } if err = json.Unmarshal([]byte(content), &dynamicEvent.config); err != nil { log.Warnf("initDynamicEvent error %v", content) return } if dynamicEvent.config == nil { err = errors.New("exception in obtaining dynamic config, config is nil") return } // 开始监听动态配置变化 return cfgCenter.ListenChanges("dynamicConfig", group, func(namespace, group, dataId, newContent string) { var newConfig map[string]interface{} if err = json.Unmarshal([]byte(newContent), &newConfig); err != nil { // 解析配置出错,打印错误日志并返回 log.Errorf("error parsing dynamic config for listen, err:%+v, newContent:%v", err, newContent) return } log.Infof("initDynamicEvent content %v", newContent) keys := CompareMaps(dynamicEvent.config, newConfig) if len(keys) == 0 { return } dynamicEvent.Lock() defer dynamicEvent.Unlock() dynamicEvent.config = newConfig for _, key := range keys { dynamicEvent.CallBack(key) } }) } // CallBack 触发一个分组的事件回调 func (e *event) CallBack(key string) { val := e.config[key] if cbfs, ok := e.list[key]; ok { for _, f := range cbfs { val2, err := deepcopy.Copy(val) if err != nil { log.Errorf("CallBack deepcopy error %v", err) } f(key, val2) } } } // CompareMaps 检查old 和 new 中每个 key 的值是否相等,返回不相等的key列表 func CompareMaps(old, new map[string]interface{}) (diffKeys []string) { if new == nil { return } for key := range old { value2, ok := new[key] if ok && !reflect.DeepEqual(old[key], value2) { diffKeys = append(diffKeys, key) } } for key := range new { if _, ok := old[key]; !ok { diffKeys = append(diffKeys, key) } } return diffKeys } // RegisterAndCall 往一个分组中注册事件并触发一次事件回调 // 这里的 keyGroup 表示一个配置键,同一个键可以有多个回调方法注册。 // 当键发生变化时,会触发该键下所有注册的回调事件。 func RegisterAndCall(key string, callback EventFunc) { dynamicEvent.Lock() defer dynamicEvent.Unlock() val := dynamicEvent.config[key] val2, err := deepcopy.Copy(val) if err != nil { log.Fatalf("RegisterAndCall deepcopy error %v", err) } dynamicEvent.list[key] = append(dynamicEvent.list[key], callback) callback(key, val2) }