Scut:通用配置管理器
1. 配置节 ConfigSection
private List<ConfigNode> _configNodes; public class ConfigNode
{
public ConfigNode()
{ } public ConfigNode(string key, string value)
{
Key = key;
Value = value;
} public string Key { get; set; }
public string Value { get; set; }
}
可知,使用一个 key-value 型的链表结构来管理 基础配置。
ConSection 里包含了对链表的操作:
public class ConfigSection
{
private List<ConfigNode> _configNodes; //配置域管理一个配置链表
public int NodeCount { get { return _configNodes == null ? : _configNodes.Count; } } public void AddNode(ConfigNode node); //加载一个配置节点
public ConfigNode GetNode(string key); //获取“key”对应的配置节点
public bool SetValue(string key, string value); //为“key”对应的节点设置“value”
public bool RemoveKey(string key); //删除“key”对应的配置节点
public void Load(string nodeString); //批量加载“key=value;key=value”格式的配置节点
}
连接配置节:最重要的是增加了对“目标连接”的管理。
public class ConnectionSection : ConfigSection
{
public string Name { get; set; }
public string ProviderName { get; set; }
public string ConnectionString { get; set; } public ConnectionSection(string name, string providerName, string connectionString)
{
Load(name, providerName, connectionString);
} public void Load(string name, string providerName, string connectionString)
{
Name = name;
ProviderName = providerName;
ConnectionString = connectionString;
}
}
2. 配置的抽象
public interface IConfigger : IDisposable
{
void Install(); //加载配置
void Reload(); //重载配置
T GetFirstConfig<T>() where T : ConfigSection; //获取首个配置
T GetFirstOrAddConfig<T>() where T : ConfigSection, new(); //获取首个配置, 如果没有则初始化
IList<ConfigSection> GetAllConfig();
T GetConnetion<T>(string name) where T : ConnectionSection;
}
数据配置:首先数据配置域管理了配置节的集合。
private readonly List<ConfigSection> _dataList = new List<ConfigSection>(); public IList<T> GetConfig<T>() where T : ConfigSection
{
lock (_dataList)
{
return _dataList.OfType<T>().ToList(); //在集合中筛选出指定类型的集合
}
} /* 针对 _dataList 的增删改查 */
protected virtual void DoClearData();
public IList<ConfigSection> GetAllConfig();
protected void AddNodeData(ConfigSection nodeData);
protected virtual void DoClearData()
下面来看更重要的几个变量与功能:
private FileSystemWatcher _watcher;
private HashSet<string> _changedFiles = new HashSet<string>();
private Timer _excuteTimer;
protected virtual void InitDependenceFile()
{
_excuteTimer = new Timer(OnExcute, null, Timeout.Infinite, Timeout.Infinite);
string path = Path.GetDirectoryName(ConfigFile) ?? "";
if (!Directory.Exists(path))
{
return;
}
string file = Path.GetFileName(ConfigFile) ?? "*.config";
_watcher = new FileSystemWatcher(path, file); //对配置文件的目录与文件进行监控
_watcher.Changed += new FileSystemEventHandler(OnWatcherChanged); //文件创建、修改、删除都会触发 “文件修改事件”
_watcher.Created += new FileSystemEventHandler(OnWatcherChanged);
_watcher.Deleted += new FileSystemEventHandler(OnWatcherChanged);
_watcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.Size;
_watcher.IncludeSubdirectories = false; //是否级联监视指定路径的子目录--否
_watcher.EnableRaisingEvents = true; //是否开启监控--是
IsDependenced = true;
}
开启配置文件监控,注册监控事件,如果配置文件发生改变,则触发事件。
public void Install()
{
if (!string.IsNullOrEmpty(ConfigFile) && File.Exists(ConfigFile))
{
InitDependenceFile();
}
LoadConfigData();
}
启用该配置,则先开启配置文件监控,之后再装订配置数据。
那么我们要关注的则是如何文件发生改变后做了什么事。
private void OnWatcherChanged(object sender, FileSystemEventArgs e)
{
try
{
_changedFiles.Add(e.FullPath);
_excuteTimer.Change(_dueChangeTime, Timeout.Infinite); //过 _dueChangeTime 这段时间后重新启动定时器
}
catch (Exception ex)
{
TraceLog.WriteError("XmlDataConfigger changed error:{0}", ex);
}
}
定时器的定时处理函数为:
private void OnExcute(object state)
{
try
{
//Repetitive loading process
var tempFile = Interlocked.Exchange(ref _changedFiles, new HashSet<string>()); //以原子操作的形式将 _changedFiles 的值清空并返回 _changedFiles 的原始值 foreach (var fileName in tempFile)
{
var e = new ConfigChangedEventArgs() { FileName = fileName };
ConfigManager.OnConfigChanged(this, e); //由总配置管理器来发布该订阅--“该文件已发生改变”
Reload();
break; }
//stop timer
_excuteTimer.Change(Timeout.Infinite, Timeout.Infinite);
}
catch (Exception ex)
{
TraceLog.WriteError("XmlDataConfigger excute error:{0}", ex);
}
}
public void Reload()
{
lock (_dataList)
{
DoClearData();
LoadConfigData(); //重新装订配置
}
TraceLog.WriteLine("{0} The configger has reloaded.", DateTime.Now.ToString("HH:mm:ss"));
var e = new ConfigReloadedEventArgs();
ConfigManager.OnConfigReloaded(this, e); //由总配置管理器来发布订阅--“该文件已重新加载”
}
线索都集中到了 ConfigManager 的事件通知器了
ConfigManager.OnConfigChanged(this, e);
ConfigManager.OnConfigReloaded(this, e);
看来 ConfigManager 可以 对所管理的任意配置文件的修改 做出反馈。
另外还有重要的现象:
public string ConfigFile { get; set; }
在 DataConfigger 里没有任何 API 对齐进行管理。
protected abstract void LoadConfigData();
还有抽象接口并没有实现。
也就意味着,DataConfigger 算是 配置抽象的基础封装, ConfigFile 与 LoadConfigData() 是留给其子类使用的,针对具体类型还会有具体的配置封装。
留下一个疑问,监控文件的为什么要用哈希表结构 HashSet<string> _changedFiles ?
从 Scut 来看,它监控唯一的配置文件 GameServer.exe.config 就好了,但如果监控的是一系列文件(FileSystemWatcher 有这个能力),就可以通知 ConfigManager 具体是哪个文件修改了。
4. 配置域管理器
private static HashSet<IConfigger> _configgerSet; //ConfigManager 统一管理各配置
private static IConfigger _configger; public static T GetConfigger<T>() where T : IConfigger //按配置类型 来检索获取 配置
{
return (T)GetConfigger(typeof(T));
} public static IConfigger GetConfigger(Type type)
{
lock (syncRoot)
{
foreach (IConfigger configger in _configgerSet)
{
if (configger.GetType() == type)
{
_configger = configger;
return configger;
}
} instance.Install(); //正如之前所分析, install 负责开启对配置文件的监控 与 该配置域的首次参数装订
_configgerSet.Add(instance);
_configger = instance;
return instance;
}
}
除此之外,还有两个事件可以让使用者对文件修改做出监控反馈:
public static event EventHandler<ConfigChangedEventArgs> ConfigChanged;
public static event EventHandler<ConfigReloadedEventArgs> ConfigReloaded;
从配置管理器也可以从 “App.config” 直接启动并生效整套配置:
public static bool Intialize(string sectionName)
{
lock (syncRoot)
{
var section = ConfigurationManager.GetSection(sectionName); //在App.config中查到对应名称的配置
if (section is IConfigger)
{
var instance = section as IConfigger;
instance.Install(); //设置文件监控、首次装订参数
_configgerSet.Add(instance); //纳入配置管理器的管理
_configger = instance;
return true;
}
return false;
}
}
插入一个与此关联的 Scut 的配置启动流程:
static EnvironmentSetting() //可以同时有静态构造函数(类级别)与普通构造函数(实例级别)
{
bool result;
try
{
result = ConfigManager.Intialize("appServerConfigger"); //先从 app.config 中尝试加载配置 “appServerConfigger”
}
catch (Exception)
{
result = false;
}
if (!result) //配置文件加载失败则加载自带的默认配置
{
try
{
ConfigManager.GetConfigger<DefaultAppConfigger>();
}
catch (Exception ex)
{
TraceLog.WriteError("Configger init error:{0}", ex);
}
}
LoadDecodeFunc();
}
由此我们可以控制 是否从外部配置文件启动。
5. App.config 的使用封装 -- ConfigUtils
public class ConfigUtils
{ public static NameValueCollection SettingsCollection
{
get
{
return ConfigurationManager.AppSettings;
}
} private ConfigUtils()
{
} public static int GetSetting(string key, int defaultValue)
{
int result = defaultValue;
try
{
object obj = SettingsCollection[key];
result = obj == null ? defaultValue : obj.ToInt();
}
catch { }
return result;
}
}
Scut:通用配置管理器的更多相关文章
- 一个简单的配置管理器(SettingManager)
在很多.net开发的项目中,我们几乎都会使用到一些自定义的参数,比如说第三方的配置参数之类的. 他们的特点是:1.系统全局 2,可以做成键值对(Dictionary). 我们可以将这些参数放到Web. ...
- 【2016-10-27】【坚持学习】【Day14】【VS 配置管理器 AssemblyInfo 】
有这样一个需求,不同客户,有不同的逻辑,通过配置管理器和条件编译进行 自动执行正确的代码.
- Win8、Win10进入SQL server配置管理器
使用 WIN8.WIN10 访问 SQL Server 配置管理器 因为 SQL Server 配置管理器是 Microsoft 管理控制台程序的一个管理单元而不是单独的程序,所以,当运行 Windo ...
- 如何启动 SQL Server Agent(SQL Server 配置管理器)
如何启动 SQL Server Agent(SQL Server 配置管理器) SQL Server 2008 R2 其他版本 4(共 6)对本文的评价是有帮助 - 评价此主题 可以从 SQL S ...
- Microsoft SQL Server,错误:2;SQL Server配置管理器(本地)—远程过程调用失败
本机是先安装sqlserver2008,后安装vs2012 在安装sqlserver2008后,运行sqlserver2008正常,接着安装vs2012,再运行sqlserver2008,问题出现了, ...
- 将 SQL Server 实例设置为自动启动(SQL Server 配置管理器)
本主题说明如何使用 SQL Server 配置管理器在 SQL Server 2012 中将 SQL Server 实例设置为自动启动. 在安装过程中,SQL Server 通常配置为自动启动. 如果 ...
- Windows10中“SQL Server 配置管理器”哪去了?
SQL Server 配置管理器是一种工具,用于管理与 SQL Server 相关联的服务.配置 SQL Server 使用的网络协议以及从 SQL Server 客户端计算机管理网络连接配置.SQL ...
- python 通用装饰器,带有参数的装饰器,
# 使用装饰器对有返回值的函数进行装饰# def func(functionName): # print('---func-1----') # def func_in(): # print(" ...
- 如果SQL Server 配置管理器没有找到就代表安装失败?
如果SQL Server 配置管理器没有找到就代表安装失败? 2017-05-09 17:58 124人阅读 评论(0) 收藏 举报 版权声明:本文为博主原创文章,未经博主允许不得转载. 首先,只要你 ...
随机推荐
- [置顶] [混迹IT职场系列]一、转正的那些事儿
讲起转正,是每个IT人进入职场后要面对的第一关,只有越过这第一关卡才能更加顺利玩弄职场或被职场玩弄或互相玩弄. 很多人觉得转正只需自身努力即可,譬如有句话叫做 “只要功夫深,铁针磨成棒”.其实不然,职 ...
- Hibernate三 关联关系
Hibernate的关联映射 客观世界中很少有对象是独立存在的,比如我们可以通过某个老师获取该老师教的所有学生,我们也可以通过某个学生获得教他的对应的老师,实体之间的互相访问就是关联关系.在Hiber ...
- 禁止执行某些讨厌的程序,如tadb.exe
第一步:首先通过快捷键"Win+R"来打开"执行"菜单. 第二步:输入"gpedit.msc"回车确认,进入我们电脑中的组策略编辑器. 第三 ...
- Linux shell入门基础(五)
五.bash运算及启动脚本 01.使用bash的命令历史 #history …… #set(显示所有的变量) | grep HIS HISTFILE=/root/.bash_history HISTF ...
- struts2常用的常量constant(转)
原文地址:http://blog.csdn.net/wfcaven/article/details/5937548 常用的常量配置 struts.serve.static.browserCache ...
- POJ 2559 Largest Rectangle in a Histogram (单调栈或者dp)
Largest Rectangle in a Histogram Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 15831 ...
- BaseBean构造
package cn.jsonlu.passguard.model; import cn.jsonlu.passguard.utils.MD5Util; import com.fasterxml.ja ...
- .NET获取机器信息
/// <summary> /// using System.Web; /// using System.Management; /// </summary> public s ...
- 如何修改mtk android 默认拍照size
[DESCRIPTION] 修改默认拍照size [SOLUTION] 修改默认的capture size,改变camera feature table的FID_CAP_SIZE default值不起 ...
- c - 向一个排序好的数组插入一个数,插入后数组依然是排序好的
概述 因为这里只是演示插入1个数,这里我不用malloc再重新分配,而是将原先数组的腾出一个占位符. 完整代码如下: #include <stdio.h> #define LEN 6 // ...