Discuz!NT 慢慢分析之开篇Config 的实现

其实很早的时候就想琢磨下Discuz!NT的一些东西,今天着重吧Discuz 的有关于配置的信息研究了下,拿出来与大家共同分享下

Discuz!NT在web.config自定义了httpModule 模块去实现了IHttpModule

<httpModules>
    <add type="Discuz.Forum.HttpModule, Discuz.Forum" name="HttpModule" />
</httpModules>
这样的话,在程序启动的时候,则首先执行此处的HttpModule里的Init方法
 public void Init(HttpApplication context)
 {
     OnlineUsers.ResetOnlineList();
     context.BeginRequest += new EventHandler(ReUrl_BeginRequest);
     if (eventTimer == null && ScheduleConfigs.GetConfig().Enabled)
     {

EventLogs.LogFileName = Utils.GetMapPath(string.Format("{0}cache/scheduleeventfaildlog.config",

BaseConfigs.GetForumPath));

         EventManager.RootPath = Utils.GetMapPath(BaseConfigs.GetForumPath);

eventTimer = new Timer(new TimerCallback(ScheduledEventWorkCallback), context.Context,

60000, EventManager.TimerMinutesInterval * 60000);

     }
     context.Error += new EventHandler(Application_OnError);
 }

一行一行的讲解:

OnlineUsers.ResetOnLineList首先将用户信息清零

context.BeginRequest += new EventHandler(ReUrl_BeginRequest) 这行代码指定地址请求处理的方法(ReUrl_BeginRequest这个方法是处理URL 地址的)

if(eventTimer == null && ScheduleConfigs.GetConfig().Enabled) 判断是否配置开启了“计划任务”且计时器是否初始化

如果开启了“计划任务”且计时器未启动,则启用计划任务信息

最后context.Error += new EventHandler(Application_OnError) 为异常处理

这是上面的是大方向,今天就说一个地方:ScheduleConfigs.GetConfig()这句话,

也就是Discuz!NT 采用的配置文件方式

Discuz!NT 将配置文件大部分的放入了web底下的config 目录里了,当然还有个最主要的DNT.Config放在外面

image

里面的结构大致如下所示

image

介绍下各个类的作用     

ScheduleConfigs 是对外部公开的对象,它仅有两个功能,一是读出配置文件,二是存储配置文件信息,均无参数/

ScheduleConfigInfo 是一个领域模型,对应相应配置的config,为了统一方便处理,这里实现了仅作规定约束的IConfigInfo接口,此接口没有任何内容。

实现ScheduleConfigs 中的功能主要依赖于

ScheduleConfigFileManager,其中用static 存储配置信息,由于是static型的,则只需要存储一次即可供全局共享

大概就是这样,后来我把Discuz!NT 的配置单独抽出来了,大概是这样的样子的

image

在这里我只向外部暴露DeclareDatertimeConfigs   这个类,其余的都为internal

部分代码如下

    public class DeclareDateTimeConfigs
    {
 
        /// <summary>
        /// 获取配置类实例
        /// </summary>
        /// <returns></returns>
        public static DeclareDateTimeConfigInfo GetConfig()
        {
            return DeclareDateTimeConfigFileManager.LoadConfig();
        }
 
        /// <summary>
        /// 保存配置类实例
        /// </summary>
        /// <returns></returns>
        public static bool SaveConfig(DeclareDateTimeConfigInfo declareDateTimeConfigInfo)
        {
            DeclareDateTimeConfigFileManager scfm = new DeclareDateTimeConfigFileManager();
            DeclareDateTimeConfigFileManager.ConfigInfo = declareDateTimeConfigInfo;
            return scfm.SaveConfig();
        }
 
 
    }
    internal class DeclareDateTimeConfigFileManager:DefaultConfigFileManager
    {
        private static DeclareDateTimeConfigInfo m_configinfo;
 
        /// <summary>
        /// 锁对象
        /// </summary>
        private static object m_lockHelper = new object();
 
        /// <summary>
        /// 文件修改时间
        /// </summary>
        private static DateTime m_fileoldchange;
 
        /// <summary>
        /// 初始化文件修改时间和对象实例
        /// </summary>
        static DeclareDateTimeConfigFileManager() {
            m_fileoldchange = System.IO.File.GetLastWriteTime(ConfigFilePath);
            m_configinfo = (DeclareDateTimeConfigInfo)DefaultConfigFileManager.DeserializeInfo(ConfigFilePath, typeof(DeclareDateTimeConfigInfo));
 
        }
        public new static IConfigInfo ConfigInfo
        {
            get { return m_configinfo; }
            set { m_configinfo = (DeclareDateTimeConfigInfo)value; }
        }
 
        /// <summary>
        /// 配置文件所在路径
        /// </summary>
        public static string filename = null;
 
 
        /// <summary>
        /// 获取配置文件所在路径
        /// </summary>
        public new static string ConfigFilePath
        {
            get
            {
                if (filename == null)
                {
                    {
                        filename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config\\DeclareDateTime.config");
                    }
 
                    if (!File.Exists(filename))
                    {
                        throw new Exception("发生错误: 虚拟目录或网站根目录下没有正确的DNT.config文件");
                    }
                }
                return filename;
            }
 
        }
 
        /// <summary>
        /// 加载配置类
        /// </summary>
        /// <returns></returns>
        public static DeclareDateTimeConfigInfo LoadConfig()
        {
            ConfigInfo = DefaultConfigFileManager.LoadConfig(ref m_fileoldchange, ConfigFilePath, ConfigInfo);
            return ConfigInfo as DeclareDateTimeConfigInfo;
        }
 
        /// <summary>
        /// 加载真正有效的配置类
        /// </summary>
        /// <returns></returns>
        public static DeclareDateTimeConfigInfo LoadRealConfig()
        {
            ConfigInfo = DefaultConfigFileManager.LoadConfig(ref m_fileoldchange, ConfigFilePath, ConfigInfo, false);
            return ConfigInfo as DeclareDateTimeConfigInfo;
        }
 
        /// <summary>
        /// 保存配置
        /// </summary>
        /// <returns></returns>
        public override bool SaveConfig()
        {
            return base.SaveConfig(ConfigFilePath, ConfigInfo);
        }
    }
    internal class DefaultConfigFileManager
    {
        /// <summary>
        /// 文件所在路径变量
        /// </summary>
        private static string m_configfilepath;
 
        /// <summary>
        /// 临时配置对象变量
        /// </summary>
        private static IConfigInfo m_configinfo = null;
 
        /// <summary>
        /// 锁对象
        /// </summary>
        private static object m_lockHelper = new object();
 
 
        /// <summary>
        /// 文件所在路径
        /// </summary>
        public static string ConfigFilePath
        {
            get { return m_configfilepath; }
            set { m_configfilepath = value; }
        }
 
 
        /// <summary>
        /// 临时配置对象
        /// </summary>
        public static IConfigInfo ConfigInfo
        {
            get { return m_configinfo; }
            set { m_configinfo = value; }
        }
 
        /// <summary>
        /// 加载(反序列化)指定对象类型的配置对象
        /// </summary>
        /// <param name="fileoldchange">文件加载时间</param>
        /// <param name="configFilePath">配置文件所在路径</param>
        /// <param name="configinfo">相应的变量 注:该参数主要用于设置m_configinfo变量 和 获取类型.GetType()</param>
        /// <returns></returns>
        protected static IConfigInfo LoadConfig(ref DateTime fileoldchange, string configFilePath, IConfigInfo configinfo)
        {
            return LoadConfig(ref fileoldchange, configFilePath, configinfo, true);
        }
 
 
        /// <summary>
        /// 加载(反序列化)指定对象类型的配置对象
        /// </summary>
        /// <param name="fileoldchange">文件加载时间</param>
        /// <param name="configFilePath">配置文件所在路径(包括文件名)</param>
        /// <param name="configinfo">相应的变量 注:该参数主要用于设置m_configinfo变量 和 获取类型.GetType()</param>
        /// <param name="checkTime">是否检查并更新传递进来的"文件加载时间"变量</param>
        /// <returns></returns>
        protected static IConfigInfo LoadConfig(ref DateTime fileoldchange, string configFilePath, IConfigInfo configinfo, bool checkTime)
        {
            lock (m_lockHelper)
            {
                m_configfilepath = configFilePath;
                m_configinfo = configinfo;
 
                if (checkTime)
                {
                    DateTime m_filenewchange = System.IO.File.GetLastWriteTime(configFilePath);
 
                    //当程序运行中config文件发生变化时则对config重新赋值
                    if (fileoldchange != m_filenewchange)
                    {
                        fileoldchange = m_filenewchange;
                        m_configinfo = DeserializeInfo(configFilePath, configinfo.GetType());
                    }
                }
                else
                    m_configinfo = DeserializeInfo(configFilePath, configinfo.GetType());
 
                return m_configinfo;
            }
        }
 
 
        /// <summary>
        /// 反序列化指定的类
        /// </summary>
        /// <param name="configfilepath">config 文件的路径</param>
        /// <param name="configtype">相应的类型</param>
        /// <returns></returns>
        public static IConfigInfo DeserializeInfo(string configfilepath, Type configtype)
        {
            return (IConfigInfo)SerializationHelper.Load(configtype, configfilepath);
        }
 
        /// <summary>
        /// 保存配置实例(虚方法需继承)
        /// </summary>
        /// <returns></returns>
        public virtual bool SaveConfig()
        {
            return true;
        }
 
        /// <summary>
        /// 保存(序列化)指定路径下的配置文件
        /// </summary>
        /// <param name="configFilePath">指定的配置文件所在的路径(包括文件名)</param>
        /// <param name="configinfo">被保存(序列化)的对象</param>
        /// <returns></returns>
        public bool SaveConfig(string configFilePath, IConfigInfo configinfo)
        {
            return SerializationHelper.Save(configinfo, configFilePath);
        }
    }
    internal class SerializationHelper
    {
        private SerializationHelper()
        { }
 
        private static Dictionary<int, XmlSerializer> serializer_dict = new Dictionary<int, XmlSerializer>();
 
        public static XmlSerializer GetSerializer(Type t)
        {
            int type_hash = t.GetHashCode();
 
            if (!serializer_dict.ContainsKey(type_hash))
                serializer_dict.Add(type_hash, new XmlSerializer(t));
 
            return serializer_dict[type_hash];
        }
 
 
        /// <summary>
        /// 反序列化
        /// </summary>
        /// <param name="type">对象类型</param>
        /// <param name="filename">文件路径</param>
        /// <returns></returns>
        public static object Load(Type type, string filename)
        {
            FileStream fs = null;
            try
            {
                // open the stream...
                fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                XmlSerializer serializer = new XmlSerializer(type);
                return serializer.Deserialize(fs);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (fs != null)
                    fs.Close();
            }
        }
 
 
        /// <summary>
        /// 序列化
        /// </summary>
        /// <param name="obj">对象</param>
        /// <param name="filename">文件路径</param>
        public static bool Save(object obj, string filename)
        {
            bool success = false;
 
            FileStream fs = null;
            // serialize it...
            try
            {
                fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
                XmlSerializer serializer = new XmlSerializer(obj.GetType());
                serializer.Serialize(fs, obj);
                success = true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (fs != null)
                    fs.Close();
            }
            return success;
 
        }
 
        /// <summary>
        /// xml序列化成字符串
        /// </summary>
        /// <param name="obj">对象</param>
        /// <returns>xml字符串</returns>
        public static string Serialize(object obj)
        {
            string returnStr = "";
            XmlSerializer serializer = GetSerializer(obj.GetType());
            MemoryStream ms = new MemoryStream();
            XmlTextWriter xtw = null;
            StreamReader sr = null;
            try
            {
                xtw = new System.Xml.XmlTextWriter(ms, Encoding.UTF8);
                xtw.Formatting = System.Xml.Formatting.Indented;
                serializer.Serialize(xtw, obj);
                ms.Seek(0, SeekOrigin.Begin);
                sr = new StreamReader(ms);
                returnStr = sr.ReadToEnd();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (xtw != null)
                    xtw.Close();
                if (sr != null)
                    sr.Close();
                ms.Close();
            }
            return returnStr;
 
        }
 
        public static object DeSerialize(Type type, string s)
        {
            byte[] b = System.Text.Encoding.UTF8.GetBytes(s);
            try
            {
                XmlSerializer serializer = GetSerializer(type);
                return serializer.Deserialize(new MemoryStream(b));
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }

使用时候非常方便,使用下列语句

            var config = DeclareDateTimeConfigs.GetConfig();

即可得到配置信息

存储配置信息也很简单  

            DeclareDateTimeConfigs.SaveConfig(config);

   因为此处是static   所以可以不用考虑缓存的问题

原文地址:https://www.cnblogs.com/jicheng1014/p/1933402.html