现在的位置: 首页 > 综合 > 正文

分享CommunityServer(2)–Configuration

2013年08月18日 ⁄ 综合 ⁄ 共 12616字 ⁄ 字号 评论关闭
 

 CommunityServer如何体现“重配置、轻编程”Config实现
.net同java2以后的编程一样,开始强调“重配置、轻编程”了,所以出现了.config类别的扩展名。通常,我们的配置信息不多,所以会写入到web.config上,但是CS的配置信息比较多,所以单独设定了一个 communityserver.config 文件来存储和配置系统的设定信息。
解析该config文件的类是
CSConfiguration.cs
该类是整站各模块部分用来实现系统灵活性的基础工具类,这样需要确保协同各模块必须保持配置的一致性,这样,自然选择了单例模式来实现类。第二个需要学习的是,既然配置信息如此重要,会影响性能,所以配置类被进行了缓存。看看如何进行单例实例化的:
 
public static CSConfiguration GetConfig()
         {
              CSConfiguration config = CSCache.Get(CacheKey) as CSConfiguration;
              if(config == null)
              {
                   string path = null;
                HttpContext context = HttpContext.Current;
                   if(context != null)
                       path = context.Server.MapPath("~/communityserver.config");
                   else
                       path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "communityserver.config");
 
                   XmlDocument doc = new XmlDocument();
                   doc.Load(path);
                   config = new CSConfiguration(doc);
                   CSCache.Max(CacheKey,config,new CacheDependency(path));
 
                   CSCache.ReSetFactor(config.CacheFactor);
                //CSEvents.PostConfigurationInitialized(config);
              }
              return config;
           
        }
首先,检查cache中是否存在已经实例化,如果实例化存在 就直接返回;如果不存在,就开始进行实例化过程。
当然,具体的实例化采用携带XmlDocument实例的构造函数来,你也可以通过public构造函数来获取实例,也就是可以new 但是,看该类的代码,应该是通过GetConfig来获取比较合适了。
进入构造函数,就开始读取XML进入config的实例内部成员设定了,根据遇到的节点不同,分别调用相应的处理函数,在具体的针对各节的处理函数里面来按照XML节点的格式来读取设定配置。如果要写关于配置文件的设定帮助文档的话,那么就需要查看源代码的实现细节了。
通常情况下,如果是收集,就用Hashtable来存储,少量采用数组。
 
除了CSConfig类外,各个组件工程也都有自己的配置处理对象。逐一来看看。
在CommunityServer.config中 有关于各个组件的配置节:
<Gallery
              allowEncodedUnicodeCharsInMetadata="true"
              >
                 <AttachmentSettings
                     enableFileSystemStorage="true"fileSystemStorageLocation="~/photos/storage"
                     enableDataStoreStorage="true" enableDirectLinks="false"
                     extensions="gif,jpg,jpeg,png,bmp,GIF,JPEG,JPG,PNG,BMP,Gif,Jpg,Jpeg,Png,Bmp"/>
                 <CacheSettings
                     enableFileSystemStorage="true"fileSystemStorageLocation="~/photos/cache"
                     enableDataStoreStorage="false" enableDirectLinks="false"
                     />
          </Gallery>
该节对应Gallery的配置处理。
        
 
          <Weblog
              defaultTheme="default"enableSkinCache="true"enableThemes="true"
              aggregatePostSize="250"createDirectories="true"enableCommentRedirects="true"
              servicePostCountLimit="25"aggregatePostCount="25"individualPostCount="15"
              authenticateOnSectionNotFound="false">
                 <AttachmentSettings
                     enableFileSystemStorage="true"fileSystemStorageLocation="~/blogs/files"
                     enableDataStoreStorage="true" enableDirectLinks="false"
                     extensions="zip,xml,txt,gif,jpg,jpeg,png,doc,xls,mp3,mmv"/>
                   <DefaultPingServices>
                       <addurl="http://rpc.weblogs.com/RPC2"/>
                       <addurl="http://ping.blo.gs/"/>
                       <addurl="http://rpc.technorati.com/rpc/ping"/>
                       <addurl="http://xping.pubsub.com/ping"/>
                   </DefaultPingServices>
         </Weblog>
      该节对应Weblog的配置处理
 
 
          <Forums>
                   <AttachmentSettings
                     enableFileSystemStorage="true"fileSystemStorageLocation="~/forums/storage"
                     enableDataStoreStorage="true" enableDirectLinks="true"/>
          </Forums>
         该节对应Forums的配置处理
               
 
          <FileGalleries>
                   <AttachmentSettings
                     enableFileSystemStorage="true"fileSystemStorageLocation="~/files/storage"
                     enableDataStoreStorage="true" enableDirectLinks="false"
                     extensions="all"/>
          </FileGalleries>
         该节对应文件共享文件夹的配置处理
 
         <Adsroles="SystemAdministrator"enable="false"/>
         该节对应系统广告块的配置处理
 
          
         <SpamautoModerateScore="5"autoDeleteScore="10"></Spam>
         该节对应系统插件块的配置处理
 
          
          <ReaderLastModifiedInterval="60"
                   roles="SystemAdministrator;FeedReaderAdministrator"
                   >
              <BlogRollerTruncationLength="500"/>
          </Reader>
              该节对应在线阅读的配置处理
 
              CommunityServer.Components. ApplicationConfiguration是全部组件的配置文件的基类。详细在注释中理解吧
[Serializable]
    public abstract class ApplicationConfiguration
     {
         public ApplicationConfiguration(){}
         //保护的静态 instance方法,显然想单例模式吧
        protected static ApplicationConfiguration Instance(Type type, bool useCache)
        {
            ApplicationConfiguration config = null;//实力本身           
            if(useCache)
            {//这个Type应该是代表当前的 ApplicationConfiguration 的某个子类的类型,如果使用了Cache就从CSCache中获取该配置类的子类实例
                config = CSCache.Get(CacheKey(type)) as ApplicationConfiguration;
            }
 
            if(config == null)
            { //如果实例null那么通过反射 来创建实例,并获得该类的基类
                config = Activator.CreateInstance(type) as ApplicationConfiguration;
                if(config != null)
                {//如果实例化成功,那么进行子类的个性化处理,也就是执行CSConfiguration.GetConfig().GetConfigSection config.ConfigSection代表子类对应于CommunityServer.config的相应配置节
                    XmlNode node = CSConfiguration.GetConfig().GetConfigSection(config.ConfigSection);
                    config.BaseSettings(node);    //调用基础设定,也就是 ApplicationConfiguration 类的属性设定,在此方法中处理节点的设定
                    config.Initialize(node);
                    if(!config.FileOnly)     //此处语义应当是指定,当不是仅仅从配置文件获取配置信息(那说明有的配置文件是在文件意外的存储方式内获取的,我想有些blog设定配置信息应该是存储在数据库中的吧)
                    {//不错,看来这里是进行DataProvider的获取,显然是从数据存储处获取配置的处理细节了
                        CommonDataProvider dp = CommonDataProvider.Instance();
                        object config2 = dp.GetApplicationConfigurationSettings(config.ApplicationType,type);
                        Merger.Merge(config,config2); //合并细节待后
                    }
                    if(useCache)
                    {
                        CacheConfigSettings(config); //如果成功获得实例咱们就Cache之
                    }
                }
                CSEvents.PostConfigurationInitialized(config);     //记录下初始化事件,应该是为了调试系统而设定的吧
            }
            return config;
        }
 
        private static string CacheKey(Type type) //唯一的明确的缓存键
        {
            return string.Format("AppConfig-{0}-{1}", type.FullName,CSContext.Current.SettingsID);
        }
 
        private static void CacheConfigSettings(ApplicationConfiguration appConfig)
        {//此处是缓存当前的配置对象 参考下面的cache对象分析
            appConfig._isCached = true;
            CacheDependency dep = new CacheDependency(null, new string[]{CSConfiguration.CacheKey});
              CSCache.Remove(CacheKey(appConfig.GetType()));
              CSCache.Insert(CacheKey(appConfig.GetType()), appConfig, dep,CSCache.MinuteFactor*15);
         }
 
         ///<summary>
         /// removes the specified application configuration from the cache if it exists;
         ///</summary>
         ///<param name="type"></param>
          protected static void Flush(Type type)         //刷新缓存就是将缓存去掉,这样会重新装载缓存的
         {
              CSCache.Remove(CacheKey(type));
         }
        protected abstract string ConfigSection { get;}
        public abstract ApplicationType ApplicationType { get;}
        private bool _enabled = true;
        private bool _isLocked = false;
        private bool _allowNew = true;
        private bool _disabled = false;
        private bool _fileOnly = false;
        private bool _isCached = false;
        public bool Enabled
        {
            get{return _enabled;}
            set{_enabled = value;}
        }
        [ReadFromConfigurationFileOnly]
        public bool IsLocked
        {
            get{return _isLocked;}
        }
        [ReadFromConfigurationFileOnly]
        public bool IsCached
        {
            get{return _isCached;}
        }
        [ReadFromConfigurationFileOnly]
        public bool FileOnly
        {
            get{return _fileOnly;}
        }
        [ReadFromConfigurationFileOnly]
        public bool AllowNew
        {
            get{return _allowNew;}
        }
 
        [ReadFromConfigurationFileOnly]
        public bool Disabled
        {
            get{return _disabled;}
        }
        protected virtual void Initialize(XmlNode node)
        {        
        }
        protected void BaseSettings(XmlNode node)
        {
            if(node != null)
            {
                XmlAttribute fo = node.Attributes["fileOnly"];
                if(fo != null)
                    this._fileOnly = bool.Parse(fo.Value);
 
                XmlAttribute att = node.Attributes["enable"];
                if(att != null)
                    this.Enabled = bool.Parse(att.Value);
 
                XmlAttribute loc = node.Attributes["locked"];
                if(loc != null)
                    this._isLocked = bool.Parse(loc.Value);
 
                XmlAttribute dis = node.Attributes["disabled"];
                if(dis != null)
                    this._disabled = bool.Parse(dis.Value);
 
                XmlAttribute allownew = node.Attributes["allowNew"];
                if(allownew != null)
                    this._allowNew = bool.Parse(allownew.Value);
            }
        }
 
        public virtual void Save()        //这个只支持非文件存储的配置信息,具体是通过数据存取Provider来获取
        {
            if(!this.FileOnly)
            {
                CommonDataProvider dp = CommonDataProvider.Instance();
                dp.CreateUpdateApplicationConfigurationSettings(this.ApplicationType, this);
                //Update this copy to the cache if we are not already cached. This will not help
                //us in a cluster
                if(!this.IsCached)
                {
                    CacheConfigSettings(this);
                }
              }
       }
     }
以上的类中的字段、方法设定ReadFromConfigurationFileOnly属性的表示改元素只支持从文件获取配置信息时候的字段有效映射。
ApplicationConfiguration 是一个 abstract 类,而为了满足论坛和博客应用,衍生了ApplicationKeyApplicationConfigurationThemedApplicationKeyApplicationConfiguration
 
譬如,FileGarry是 ApplicationKeyApplicationConfiguration 而 blog是 ThemedApplicationKeyApplicationConfiguration。
下面来逐个具体的实例分析
WeblogConfiguration
该类实际上继承于 ThemedApplicationKeyApplicationConfiguration 看名字知道,这个配置是支持Theme的ApplicationKeyApplicationConfiguration,同时 ThemedApplicationKeyApplicationConfiguration 又派生自 ApplicationKeyApplicationConfiguration ,ApplicationKeyApplicationConfiguration是需要主键Key的配置文件,ApplicationKeyApplicationConfiguration最终派生自 ApplicationConfiguration,即:
WeblogConfiguration –》ThemedApplicationKeyApplicationConfiguration –》ApplicationKeyApplicationConfiguration—》ApplicationConfiguration
我们重点分析下其 构造函数和Instance方法:
public static WeblogConfiguration Instance()
        {
            return Instance(true);     //true表示需要cache
        }
 
        public static WeblogConfiguration Instance(bool useCache)
        {
            return Instance(thisType, useCache) as WeblogConfiguration; //此时调用的是最上层基类 ApplicationConfiguration 的Instance方法           
        }
该类重写的部分有:
#region Overridden Base Class Members
          protected override string ConfigSection
         {
              get { return "CommunityServer/Weblog"; }
         }
         public override ApplicationType ApplicationType
         {
              get { return ApplicationType.Weblog; }
         }
          #endregion
 
#region Initialize
          protected override void Initialize(XmlNode node)
         {
              base.Initialize(node);   //父类的Initialize
 
              if(node != null)
              {
                   ……//为 WeblogConfiguration 的个性化设置部分
              }
         }
          #endregion
          protected override string ThemeLocationDefault() { return "~/Themes/Blogs/"; }
这些覆盖的部分,通过其属性被逻辑层读取并进行运算。
 
FileGalleryConfiguration
继承结构
FileGalleryConfiguration 》ApplicationKeyApplicationConfiguration 》ApplicationConfiguration
 
 
ForumConfiguration
ForumConfiguration 》ApplicationConfiguration
其Instance 函数:
public static ForumConfiguration Instance()
        {
            return Instance(true);
        }
 
         public static ForumConfiguration Instance(bool useCache)
         {
            return Instance(thisType, useCache) as ForumConfiguration;
         }
同样通过最上的基类 ApplicationConfiguration 来实例化并缓存自己。Initialize函数加入自身的个性化的XML文件处理代码。
其他类都类似:
1、 通过 ApplicationConfiguration 的Instance函数来获得单例实例化功能
2、 通过 ApplicationConfiguration就已经定义的 Initialize函数的覆盖来实现自身的个性化数据处理。
3、 针对不同的Config的存储形式(文件或者DB),在 ApplicationConfiguration 就进行了区分,并通过DataProvider来获得具体配置信息或者XML的Node。
4、通过属性来提供配置信息的存取界面
在建立了系统的Config实例后,各个组件部分会依据自身的设计,主动读取配置信息,从而决定自身的执行流程,当然需要考虑各类不同的情况,配置情况来实现所谓的“重配置”。
阅读此类时候,将实体 Provider 类放在 该类我觉得有点不大妥当,既然都那么多文件了,也不怕多一个Provider.cs文件吧。另外,如果在定义private等一大堆成员变量的时候,能够用region来做下说明归类,我觉得可能更利于大家阅读。
这个是属于CS整体框架的基础类,所以大家需要了解其具体细节。
 
分析此类,我们也顺带阅读下CSCache类,这个集成系统提供的Cache功能的类。
由于System.Web.Caching 的Cache类是系 统提供的,而且无法继承,所以采用集成手段来OOP系统的Cache功能,也显然这样的一个类只能是类似CSConfig那样采用单例模式来实现。该Cache 有一个private 的空构造函数和静态构造函数。静态的构造函数,从HttpContext类或者HttpRuntime中获得Cache功能。
static CSCache()
        {
            HttpContext context = HttpContext.Current;
            if(context != null)
            {
                _cache = context.Cache;
            }
            else
            {
                _cache = HttpRuntime.Cache;
            }
        }
与CSCache类似,还有一个CSContext类也是属于集成系统框架的特定类,我们可对比CSCache来看看。通常,你如果使用系统提供的某类并集成的话,你都会或多或少要遵守该类的一些诸如实例生成啊等的约定。

 

抱歉!评论已关闭.