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. 阿里巴巴算法工程师四面(三轮技术+hr面)详细面经

    阿里面试总结: 一遍一遍地刷阿里网站,今天发现“面试中”变成“待跟进offer”了,写个面经攒人品,希望offer通知邮件早点来吧. 我当时投简历时投了C/C++工程师,其实也没经过啥考虑,因为我一开 ...

  2. java中的代理

    package cn.itcast.day3; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHan ...

  3. C语言判断系统数据大/小端存储方式

    小端存储:数据的低位部分,存储于存储器的低地址空间里. 大端存储:数据的低位部分,存储于存储器的高地址空间里. 首先,一般PC数据存储方式是小端存储. 基本实现思想是:将存储器中所存的数据按字节以地址 ...

  4. POJ3169 Layout(差分约束系统)

    POJ3169 Layout 题意: n头牛编号为1到n,按照编号的顺序排成一列,每两头牛的之间的距离 >= 0.这些牛的距离存在着一些约束关系:1.有ml组(u, v, w)的约束关系,表示牛 ...

  5. [每日一题] OCP1z0-047 :2013-08-14 如何理解USING INDEX?...................................41

    正确答案:B 一.USING INDEX的实验: .USING INDEX可以让你在创建主键.唯一性约束的时候使用指定的索引或创建索引.或修改索引的存储结构. OK,我先不用USING INDEX,创 ...

  6. adb出现adb server is out of date时的解决的方法

    出错的原因是adb的port被其它程序的进程占据了,所以要做的就是找到并kill该进程.步骤:. 1.在cmd中运行adb nodaemon server,查看adb的port号是多少,普通情况下是5 ...

  7. Android 开源项目android-open-project解析之(三) ScrollView,TimeView,TipView,FlipView

    九.ScrollView Discrollview 支持滚动时Item淡入淡出,平移,缩放效果的ScrollView 项目地址:https://github.com/flavienlaurent/di ...

  8. PHP安全编程:HTTP请求欺骗(转)

    一个比欺骗表单更高级和复杂的攻击方式是HTTP请求欺骗.这给了攻击者完全的控制权与灵活性,它进一步证明了不能盲目信任用户提交的任何数据. 为了演示这是如何进行的,请看下面位于http://exampl ...

  9. DM8168 坎坷硬件之路(DDR3)

    新做了8168板,调试DDR3的时候EMIF0遇到了个别数据位出错的问题 DDR3 128MB*8=1GB 我为了測试DDR3的所有空间,把地址存到DDR3中,就是*pdata++=(Uint32)p ...

  10. Android(java)学习笔记248:ContentProvider使用之虚拟短信

    1.虚拟短信应用场景:   急着脱身?应付老婆(老公.男女朋友查岗)?   使用虚拟通话短信吧.您只需通过简单设置,软件就会在指定时间会模拟一个“真实”来电或短信来迷惑对方,通过“真实”的证据让对方相 ...