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) 收藏 举报 版权声明:本文为博主原创文章,未经博主允许不得转载. 首先,只要你 ...
随机推荐
- SwingConsole
Java的Swing默认不是线程安全的,类的调度应该由线程分派器来安排.如果每个类都各个各的调度,有可能造成线程紊乱,带来一些难以检测的错误. 对于编写实验性代码(每次都只有一个JFrame),如果每 ...
- hdu 3553 Just a String (后缀数组)
hdu 3553 Just a String (后缀数组) 题意:很简单,问一个字符串的第k大的子串是谁. 解题思路:后缀数组.先预处理一遍,把能算的都算出来.将后缀按sa排序,假如我们知道答案在那个 ...
- System.Threading.Timer 使用
//定义计时器执行完成后的回调函数 TimerCallback timecallback = new TimerCallback(WriteMsg); //定义计时器 System.Threading ...
- 15、Cocos2dx 3.0游戏开发找小三之Sprite:每一个精灵都是上辈子折翼的天使
重开发人员的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/30475395 Sprite Sprite 能够说是 ...
- ZOJ3329之经典概率DP
One Person Game Time Limit: 1 Second Memory Limit: 32768 KB Special Judge There is a very ...
- android 自定义progressDialog实现
我们在项目中经常会遇到这样一个应用场景:执行某个耗时操作时,为了安抚用户等待的烦躁心情我们一般会使用进度条之类的空间,在android中让 大家最容易想到的就是progressbar或者progres ...
- JDK5-自动拆装箱
拆装箱:在基本类型与其对应的引用类型之间转换 装箱:Integer iObj = 5; 拆箱:int i = 5 + iObj; 装箱时,一个字节以内的数据在一个常量池中(小整数的使用频率高),即-1 ...
- Android(java)学习笔记240:多媒体之图形颜色的变化
1.相信大家都用过美图秀秀中如下的功能,调整颜色: 2. 下面通过案例说明Android中如何调色: 颜色矩阵 ColorMatrix cm = new ColorMatrix(); paint.se ...
- Day11 - Mysql and ORM
python 之路,Day11 - python mysql and ORM 本节内容 数据库介绍 mysql 数据库安装使用 mysql管理 mysql 数据类型 常用mysql命令 创建数据库 ...
- IOS 开发 【objective-c 基础1】
案例:读取本地硬盘上程序根目录下words.txt文件内容,显示每行的字符数. // // main.m // hello // // Created by swack on 15/11/27. // ...