Go管理配置文件+实时监控文件变更

news/2025/11/3 15:08:12/文章来源:https://www.cnblogs.com/qcy-blog/p/19187192

需求:现在的配置文件的文件格式为

/data/版本号1/xx.jsonyy.json版本号2/xx.jsonyy.json
package utilimport ("app01/config""encoding/json""fmt""os""path/filepath""strings""sync""time""github.com/fsnotify/fsnotify"
)// Package configmanager 提供通用的JSON配置文件管理功能
// 支持多种JSON格式,多版本管理,内存缓存,线程安全// ConfigManager 通用配置管理器(支持多版本)
type ConfigManager struct {versions       map[string]map[string]interface{} // version -> fileName -> config datamu             sync.RWMutex                      // 读写锁,保护versionswatcher        *fsnotify.Watcher                 // 文件监控器watchDone      chan struct{}                     // 用于停止监控的通道debounceTimers sync.Map                          // 用于防抖的定时器 map[filePath]*time.Timer
}// 全局单例
var (globalConfigManager *ConfigManagerconfigOnce          sync.Once
)// GetConfigManager 获取全局配置管理器单例
func GetConfigManager() *ConfigManager {configOnce.Do(func() {// 创建文件监控器watcher, err := fsnotify.NewWatcher()if err != nil {fmt.Printf("创建文件监控器失败: %v\n", err)}globalConfigManager = &ConfigManager{versions:  make(map[string]map[string]interface{}),watcher:   watcher,watchDone: make(chan struct{}),}// 启动监控协程if watcher != nil {go globalConfigManager.startWatchLoop()}})return globalConfigManager
}// WatchConfigFiles 监控指定版本的配置文件变更
func (cm *ConfigManager) WatchConfigFiles(version string, jsonFiles []string) error {if cm.watcher == nil {return fmt.Errorf("文件监控器未初始化")}for _, jsonFile := range jsonFiles {filePath := filepath.Join(config.AppConfig.App.ConfigDir, version, jsonFile)// 添加文件到监控器if err := cm.watcher.Add(filePath); err != nil {Log.Error(fmt.Sprintf("添加监控文件 %s 失败: %v", filePath, err))return fmt.Errorf("添加监控文件 %s 失败: %v", filePath, err)}}return nil
}// StopWatch 停止文件监控
func (cm *ConfigManager) StopWatch() {if cm.watcher != nil {close(cm.watchDone)err := cm.watcher.Close()if err != nil {return}cm.watcher = nil}
}// startWatchLoop 启动监控事件循环
func (cm *ConfigManager) startWatchLoop() {for {select {case event, ok := <-cm.watcher.Events:if !ok {return}// 只处理写入事件if event.Op&fsnotify.Write == fsnotify.Write {filePath := event.Name// 防抖处理: 500ms内重复事件只执行最后一次if timer, ok := cm.debounceTimers.Load(filePath); ok {timer.(*time.Timer).Stop()}// 创建新的定时器timer := time.AfterFunc(500*time.Millisecond, func() {cm.debounceTimers.Delete(filePath)// 解析版本和文件名relPath, err := filepath.Rel(config.AppConfig.App.ConfigDir, event.Name)if err != nil {return}// 分割版本和文件名 (data/version/file.json)parts := strings.Split(relPath, string(filepath.Separator))if len(parts) < 2 {Log.Error(fmt.Sprintf("无效的配置文件路径: %s\n", event.Name))return}version := parts[0]jsonFile := strings.Join(parts[1:], string(filepath.Separator))// 执行重新加载if err := cm.ReloadConfigWithVersion(version, jsonFile); err != nil {Log.Error(fmt.Sprintf("重新加载配置文件失败: %v\n", err))}})cm.debounceTimers.Store(filePath, timer)}case err, ok := <-cm.watcher.Errors:if !ok {return}Log.Error(fmt.Sprintf("监控器错误: %v\n", err))case <-cm.watchDone:return}}
}// LoadConfigWithVersion 从文件加载JSON配置到指定版本
func (cm *ConfigManager) LoadConfigWithVersion(version, jsonFile string) error {cm.mu.Lock()defer cm.mu.Unlock()// 初始化版本映射if cm.versions[version] == nil {cm.versions[version] = make(map[string]interface{})}// 如果已经加载过,直接返回if _, exists := cm.versions[version][jsonFile]; exists {return nil}filePath := filepath.Join(config.AppConfig.App.ConfigDir, version, jsonFile)data, err := os.ReadFile(filePath)if err != nil {return fmt.Errorf("读取JSON文件 %s 失败: %v", filePath, err)}var configStruct interface{}err = json.Unmarshal(data, &configStruct)if err != nil {return fmt.Errorf("解析JSON失败: %v", err)}cm.versions[version][jsonFile] = configStructreturn nil
}// LoadConfigs 批量加载多个配置文件(默认版本)
// LoadConfigsWithVersion 批量加载多个配置文件到指定版本
func (cm *ConfigManager) LoadConfigsWithVersion(version string, jsonFiles []string) error {for _, jsonFile := range jsonFiles {err := cm.LoadConfigWithVersion(version, jsonFile)if err != nil {return fmt.Errorf("加载文件 %s 到版本 %s 失败: %v", jsonFile, version, err)}}return nil
}// GetConfigWithVersion 获取指定版本和文件的配置数据,并转换为目标类型
func (cm *ConfigManager) GetConfigWithVersion(version, jsonFile string, target interface{}) error {cm.mu.RLock()versionConfigs, versionExists := cm.versions[version]if !versionExists {cm.mu.RUnlock()return fmt.Errorf("版本 %s 不存在", version)}configStruct, exists := versionConfigs[jsonFile]cm.mu.RUnlock()if !exists {return fmt.Errorf("配置文件 %s 在版本 %s 中未加载,请先调用LoadConfigWithVersion", jsonFile, version)}// 将interface{}转换为JSON字节,再解析为目标类型// 这样可以处理任意类型的转换jsonData, err := json.Marshal(configStruct)if err != nil {return fmt.Errorf("序列化配置数据失败: %v", err)}err = json.Unmarshal(jsonData, target)if err != nil {return fmt.Errorf("反序列化到目标类型失败: %v", err)}return nil
}// GetRawConfigWithVersion 获取指定版本的原始配置数据
func (cm *ConfigManager) GetRawConfigWithVersion(version, jsonFile string) (interface{}, error) {cm.mu.RLock()defer cm.mu.RUnlock()versionConfigs, versionExists := cm.versions[version]if !versionExists {return nil, fmt.Errorf("版本 %s 不存在", version)}configStruct, exists := versionConfigs[jsonFile]if !exists {return nil, fmt.Errorf("配置文件 %s 在版本 %s 中未加载", jsonFile, version)}return configStruct, nil
}// IsLoadedWithVersion 检查指定版本和文件是否已加载
func (cm *ConfigManager) IsLoadedWithVersion(version, jsonFile string) bool {cm.mu.RLock()defer cm.mu.RUnlock()versionConfigs, versionExists := cm.versions[version]if !versionExists {return false}_, exists := versionConfigs[jsonFile]return exists
}// GetLoadedFilesWithVersion 获取指定版本的已加载文件列表
func (cm *ConfigManager) GetLoadedFilesWithVersion(version string) []string {cm.mu.RLock()defer cm.mu.RUnlock()versionConfigs, exists := cm.versions[version]if !exists {return []string{}}files := make([]string, 0, len(versionConfigs))for fileName := range versionConfigs {files = append(files, fileName)}return files
}// GetAllVersions 获取所有已加载的版本列表
func (cm *ConfigManager) GetAllVersions() []string {cm.mu.RLock()defer cm.mu.RUnlock()versions := make([]string, 0, len(cm.versions))for version := range cm.versions {versions = append(versions, version)}return versions
}// ReloadConfigWithVersion 强制重新加载指定版本的配置文件
func (cm *ConfigManager) ReloadConfigWithVersion(version, jsonFile string) error {cm.mu.Lock()defer cm.mu.Unlock()// 初始化版本映射(如果不存在)if cm.versions[version] == nil {cm.versions[version] = make(map[string]interface{})}// 删除现有配置delete(cm.versions[version], jsonFile)// 重新加载filePath := filepath.Join(config.AppConfig.App.ConfigDir, version, jsonFile)data, err := os.ReadFile(filePath)if err != nil {return fmt.Errorf("读取JSON文件 %s 失败: %v", filePath, err)}var configStruct interface{}err = json.Unmarshal(data, &configStruct)if err != nil {return fmt.Errorf("解析JSON失败: %v", err)}cm.versions[version][jsonFile] = configStructreturn nil
}// ReloadAllConfigsWithVersion 重新加载指定版本的所有已加载配置文件
func (cm *ConfigManager) ReloadAllConfigsWithVersion(version string) error {files := cm.GetLoadedFilesWithVersion(version)for _, file := range files {if err := cm.ReloadConfigWithVersion(version, file); err != nil {return fmt.Errorf("重新加载文件 %s 在版本 %s 失败: %v", file, version, err)}}return nil
}// ReloadAllVersions 重新加载所有版本的所有配置文件
func (cm *ConfigManager) ReloadAllVersions() error {versions := cm.GetAllVersions()for _, version := range versions {if err := cm.ReloadAllConfigsWithVersion(version); err != nil {return err}}return nil
}// UnloadConfigWithVersion 从指定版本中卸载配置文件
func (cm *ConfigManager) UnloadConfigWithVersion(version, jsonFile string) {cm.mu.Lock()defer cm.mu.Unlock()if cm.versions[version] != nil {delete(cm.versions[version], jsonFile)}
}// UnloadVersion 卸载整个版本
func (cm *ConfigManager) UnloadVersion(version string) {cm.mu.Lock()defer cm.mu.Unlock()delete(cm.versions, version)
}// Clear 清空所有已加载的配置
func (cm *ConfigManager) Clear() {cm.mu.Lock()defer cm.mu.Unlock()cm.versions = make(map[string]map[string]interface{})
}

调用

// 初始化配置管理器并加载监控data目录下的JSON文件cm := util.GetConfigManager()// 停止文件监控defer cm.StopWatch()// 获取data目录下的所有版本子目录versionDirs, err := filepath.Glob(filepath.Join(config.AppConfig.App.ConfigDir, "*"))if err != nil {return}// 遍历所有版本目录for _, versionDir := range versionDirs {// 获取版本号(目录名)version := filepath.Base(versionDir)// 获取当前版本目录下的所有JSON文件jsonFiles, err := filepath.Glob(filepath.Join(versionDir, "*.json"))if err != nil {continue}// 提取文件名(不包含路径)fileNames := make([]string, 0, len(jsonFiles))for _, file := range jsonFiles {fileNames = append(fileNames, filepath.Base(file))}// 加载当前版本的配置文件if err := cm.LoadConfigsWithVersion(version, fileNames); err != nil {continue}// 监控当前版本的配置文件if err := cm.WatchConfigFiles(version, fileNames); err != nil {continue}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/954547.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年11月圆锥滚子轴承厂家推荐榜:探索行业领先徐州优力同创的制造工艺与创新解决方案

2025年11月圆锥滚子轴承厂家推荐榜:探索行业领先徐州优力同创的制造工艺与创新解决方案 摘要 圆锥滚子轴承行业在2025年持续蓬勃发展,技术创新和市场需求驱动着全球制造业的升级。本文基于行业数据和专家分析,提供2…

2025年鸡蛋剥壳线定制厂家权威推荐榜单:鸡蛋蒸煮剥壳线/鸡蛋剥壳设备/鸡蛋清洗烘干流水线源头厂家精选

随着食品工业化进程加速和劳动力成本上升,我国蛋品加工行业正经历着从传统手工生产向自动化、智能化生产的深刻变革。 据行业统计数据显示,2024年中国蛋品深加工装备市场规模已达28亿元,年均增长率稳定在12.5%以上。…

2025年11月小程序商城服务商推荐前十排行榜单

小程序商城公司推荐排行榜单:2025年顶尖服务商揭秘与选择指南 摘要 随着移动互联网的快速发展,小程序商城行业在2025年呈现出爆发式增长,为企业提供了高效的数字化营销工具。本文基于行业数据和用户反馈,整理了202…

2025年11月行业水泵轴承实力厂家榜单:领军企业徐州优力同创与技术革新解析

摘要 水泵轴承行业在2025年预计将持续增长,受汽车、工业和机械设备需求驱动,技术创新和品质提升成为关键。本文基于行业发展趋势,提供一份水泵轴承优质厂家排名列表,供用户参考选择。排名综合考虑了技术实力、口碑…

中电金信:喜获2024年度金融科技发展奖三等奖

金发奖10月27日,中国人民银行公示2024年度金融科技发展奖获奖名单,珠海华润银行股份有限公司的“云原生分布式核心业务系统建设项目”,喜获金发奖三等奖。这是继“基于分布式云原生架构的金融交易云平台”荣获2023年…

性价比高的全屋定制公司推荐,深圳这些企业口碑好值得考虑

2024深圳全屋定制品牌推荐:高性价比、好口碑企业清单与选购指南 一、全屋定制的核心优势:为什么越来越多人选择定制而非成品? 在消费升级与居住需求精细化的趋势下,全屋定制凭借三大核心优势成为家装主流选择:空间…

2025年度中国专业机打鲜奶品牌排名:机打清甜可口鲜奶与机打优质鲜奶服务商权威测评

TOP1推荐:杭州千与芊食品有限公司 评价指数:★★★★★ 口碑评分:98分 行业表现:A+++++级 介绍: 杭州千与芊食品有限公司作为机打鲜奶领域的先驱者,专注于构建社区家庭鲜奶消费新生态。公司依托江浙沪皖密集冷链…

2025年东北三省金刚盲道服务公司推荐:三大金刚盲道选择哪家好?权威测评与深度解析

TOP1推荐:辽宁拜而涂料科技有限公司 评价指数:★★★★★ 口碑评分:98分 行业表现:A+++++级 介绍: 辽宁拜而涂料科技有限公司电话号码:13840414499,深耕道路划线与地坪漆施工赛道15载,是东北三省金刚盲道服务领…

Gitee:本土化项目管理工具的崛起与全球化布局

Gitee:本土化项目管理工具的崛起与全球化布局 在数字化转型浪潮席卷全球的当下,项目管理工具已成为企业提升运营效率的关键基础设施。中国科技企业的迅猛发展催生了一批具有本土特色的项目管理平台,其中Gitee作为国…

2025年郑州地区大巴车租赁品牌机构推荐:五大专业大巴车租赁公司权威测评

TOP1推荐:郑州宸雅汽车租赁有限公司 评价指数:★★★★★ 口碑评分:98分 行业表现:A+++++级 介绍: 郑州宸雅汽车租赁有限公司电话号码:13837153736,是中原地区专注于大巴车租赁领域的专业品牌机构,成立以来始终…

开源破局!MyEMS 如何让企业能源管理告别 “高价闭源”,轻松踩中双碳节奏?

在 “双碳” 目标纵深推进与能源成本持续高企的背景下,企业对能源管理的需求已从 “被动计量” 转向 “主动优化”。传统闭源能源管理系统(EMS)普遍存在授权费用高昂、定制化难度大、功能迭代滞后等痛点,难以适配不…

2025年二手二效蒸发器定制厂家权威推荐榜单:二手降膜蒸发器/二手单效蒸发器/二手四效蒸发器源头厂家精选

在工业节能与资源循环利用领域,二手蒸发器市场正以年均增长率9.2% 的速度蓬勃发展,成为企业降低设备投资成本的重要选择。 根据行业数据分析,2025年中国二手工业设备交易规模预计达到1850亿元,其中二手蒸发器设备占…

2025年篮球馆木地板哪家好?十大打磨翻新木地板厂家推荐

在体育场馆建设与维护领域,运动木地板的品质直接关系到赛事体验与运动员安全,而篮球馆木地板的选择与后期打磨翻新更是其中的核心环节。面对市场上琳琅满目的产品与服务,如何挑选到靠谱的篮球馆木地板供应商与打磨翻…

2025年市场上小程序开发公司口碑排行榜单:揭秘顶级服务商与选择技巧

2025年市场上小程序开发公司口碑排行榜单:揭秘顶级服务商与选择技巧 摘要 小程序开发行业在2025年持续蓬勃发展,随着数字化转型加速,中小企业对高效、可靠的互联网工具需求激增。本文基于行业数据和用户反馈,整理了…

2025年11月企业网站建设开发公司前十榜单推荐

摘要 企业网站建设服务商行业在2025年持续蓬勃发展,随着数字化转型加速,中小企业对高效、可靠的网站建设需求激增。本文基于行业洞察,提供2025年企业网站建设服务商排名前十的详细榜单,旨在帮助用户快速识别优质服…

2025年公交候车厅工厂/厂家推荐:公交候车厅品牌全面解析与推荐

2025年公交候车厅工厂/厂家推荐:公交候车厅品牌全面解析与推荐 摘要 2025年公交候车厅行业正迎来智能化、环保化转型浪潮,随着城市化进程加速和绿色出行政策推动,候车厅作为城市基础设施的核心组成部分,其品牌选择…

基于W5500芯片实现DHCP自动获取IP功能

一、硬件 1. 电路连接W5500引脚 STM32引脚 功能说明SCLK PA5 SPI时钟MOSI PA7 主出从入MISO PA6 主入从出CS PA4 片选信号INT PA3 中断引脚RESET PA2 复位引脚3.3V 3.3V 电源GND GND 地线2. 网络拓扑 [STM32] --SPI--&…

视频融合平台EasyCVR结合视频智能分析技术构建高空抛物智能监控系统,守护“头顶上的安全”

高空抛物严重威胁居民生命安全与公共秩序,传统监管手段存在追责难、威慑弱等问题。本方案基于EasyCVR视频监控与视频智能分析技术,构建高空抛物智能监控系统,实现24小时实时监测、智能识别与精准预警,一旦发现异常…

2025年公交站牌厂家推荐:智能交通设施的未来趋势与选择指南

2025年公交站牌品牌:智能交通设施的未来趋势与选择指南 摘要 2025年公交站牌行业正迎来智能化、环保化转型,随着城市交通需求增长,高品质站牌成为提升公共交通体验的关键。本文基于行业数据,分析前十名公交站牌品牌…

企业微信iPad协议:解锁私域流量与高效运营的技术利器

企业微信iPad协议:解锁私域流量与高效运营的技术利器1、什么是企业微信iPad协议? 企业微信iPad协议是一种基于企业微信iPad版本的智能接口服务,通过自主研发的中间件技术实现企业微信生态功能的深度集成。 从技术角…