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:通用配置管理器的更多相关文章

  1. 一个简单的配置管理器(SettingManager)

    在很多.net开发的项目中,我们几乎都会使用到一些自定义的参数,比如说第三方的配置参数之类的. 他们的特点是:1.系统全局 2,可以做成键值对(Dictionary). 我们可以将这些参数放到Web. ...

  2. 【2016-10-27】【坚持学习】【Day14】【VS 配置管理器 AssemblyInfo 】

    有这样一个需求,不同客户,有不同的逻辑,通过配置管理器和条件编译进行 自动执行正确的代码.

  3. Win8、Win10进入SQL server配置管理器

    使用 WIN8.WIN10 访问 SQL Server 配置管理器 因为 SQL Server 配置管理器是 Microsoft 管理控制台程序的一个管理单元而不是单独的程序,所以,当运行 Windo ...

  4. 如何启动 SQL Server Agent(SQL Server 配置管理器)

    如何启动 SQL Server Agent(SQL Server 配置管理器) SQL Server 2008 R2 其他版本   4(共 6)对本文的评价是有帮助 - 评价此主题 可以从 SQL S ...

  5. Microsoft SQL Server,错误:2;SQL Server配置管理器(本地)—远程过程调用失败

    本机是先安装sqlserver2008,后安装vs2012 在安装sqlserver2008后,运行sqlserver2008正常,接着安装vs2012,再运行sqlserver2008,问题出现了, ...

  6. 将 SQL Server 实例设置为自动启动(SQL Server 配置管理器)

    本主题说明如何使用 SQL Server 配置管理器在 SQL Server 2012 中将 SQL Server 实例设置为自动启动. 在安装过程中,SQL Server 通常配置为自动启动. 如果 ...

  7. Windows10中“SQL Server 配置管理器”哪去了?

    SQL Server 配置管理器是一种工具,用于管理与 SQL Server 相关联的服务.配置 SQL Server 使用的网络协议以及从 SQL Server 客户端计算机管理网络连接配置.SQL ...

  8. python 通用装饰器,带有参数的装饰器,

    # 使用装饰器对有返回值的函数进行装饰# def func(functionName): # print('---func-1----') # def func_in(): # print(" ...

  9. 如果SQL Server 配置管理器没有找到就代表安装失败?

    如果SQL Server 配置管理器没有找到就代表安装失败? 2017-05-09 17:58 124人阅读 评论(0) 收藏 举报 版权声明:本文为博主原创文章,未经博主允许不得转载. 首先,只要你 ...

随机推荐

  1. selenium grid java 资料

    Grid TestNG: 使用Selenium Grid改进Web应用程序的测试: http://www.ithov.com/server/117464.shtml

  2. Wow! Such Doge! - HDU 4847 (水题)

    题目大意:题目描述了一大堆.....然而并没什么用,其实就是让求给的所有字符串里面有多少个"doge",不区分大小写.   代码如下: ====================== ...

  3. + (void)load和+ (void)initialize有什么用处

    两个方法都可以进行一些类的初始化操作.其中有些小区别.+(void)load 方法只要加入了工程种,进行了编译,且.m中实现了这个方法,都会调用一次,值得注意的时没实现的子类是不会调用的,就算父类实现 ...

  4. Linux 数学运算

    let 命令 a= b= let c=a+B echo $c let a++ let b++ echo $a $b []方法 a= b= echo $[a+b] echo $[$a+$b] (()) ...

  5. angularjs简单实现$http.post(CORS)跨域及$http.post传参方式模拟jQuery.post

    1.开启angularjs的CORS支持 .config(function($httpProvider) { // CORS post跨域配置 $httpProvider.defaults.useXD ...

  6. OpenMP并行程序设计

    1.fork/join并行执行模式的概念 2.OpenMP指令和库函数介绍 3.parallel 指令的用法 4.for指令的使用方法 5 sections和section指令的用法 1.fork/j ...

  7. [置顶] [Android源码分析]inquiry result引起的上层变化分析

    在上一篇文章中,我们详细分析了android是如何解析蓝牙反馈上来的搜索到的设备信息,本文将会继续分析这些信息到了上层之后是如何处理. 8.inquiry result引起的上层变化 我们知道inqu ...

  8. poj 3478 The Stable Marriage Problem 稳定婚姻问题

    题目给出n个男的和n个女的各自喜欢对方的程度,让你输出一个最佳搭配,使得他们全部人的婚姻都是稳定的. 所谓不稳婚姻是说.比方说有两对夫妇M1,F1和M2,F2,M1的老婆是F1,但他更爱F2;而F2的 ...

  9. cocos2dx c++ 在mac下写的中文凝视,在win32下编译时不通过

    今天遇到个奇怪的问题,在mac下写的程序,加的中文凝视,编译没有问题,可是在win32下(使用的时vs2012, win7 64bit 系统)编译就总是报错 最后在中文凝视后 加一个空格,或者 换行, ...

  10. 会用errno,事半功倍

    参考一 参考二 参考三 参考四 一. errno二. 把errno的数字转换成相应的文字说明1. 使用strerror函数2. 使用perror函数三. errno的线程/进程安全性附录 一. err ...