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

分享CommunityServer(7) –CSModule

2013年08月06日 ⁄ 综合 ⁄ 共 6742字 ⁄ 字号 评论关闭
 

 CSModule实现的事件监听体系
CS里面的CSModule是个什么东东?
我们知道,系统大了,必然是比较复杂,系统内部很多事件需要被各个相互联系的模块相互截取,相互了解。我们要针对CS系统做出开发,实际上我们很大程度上是针对CS内部流程执行过程中的大量事件进行面向事件的处理代码编写。譬如,我们要做到系统发生了例外,我们可以敏感接获到,并且需要在特定的“安全区域”进行处理例外;再比如,我们有时候会针对某个帖子进行监控,如果发生了新帖需要被通知,如果硬编码进入当然可以,但是假若需要接获新帖通知的不止一个相关体系,那么硬编码显然不符合要求,这样,就需要一种协调机制,引入一种消息通告模型,让内部事件可以通过这种机制安全有序转入到关心事件的处理部分,这种机制在CS中就是通过CSModule来实现的。
 
CSEvent 定义了系统内大部分事件。包含了Users、Posts、Sections、Groups、PostCategories、Ratings、Favorites、Exceptions、Search、UserInvitations等对象的事件。但是每一个事件都是调用了CSApplication实例的相应事件函数。如关于Search的事件:
        public static void PreSearch(SearchQuery query)
       {
            CSApplication.Instance().ExecutePreSearch(query);
        }
 
        public static void PostSearch(SearchResultSet results)
        {
            CSApplication.Instance().ExecutePostSearch(results);
        }
 
这些事件需要在特定代码流中被触发,而这些事件会转入到 CSApplication的实例中。
CSApplication是单例模式,并且通过CSCache缓存实例。其Instance函数:
internal static CSApplication Instance()
         {
              const string key = "CSApplication";
              CSApplication app = CSCache.Get(key) as CSApplication;
              if(app == null)
              {
                   lock(sync)
                   {
                       app = CSCache.Get(key) as CSApplication;
                       if(app == null)
                       {
                            CSConfiguration config = CSContext.Current.Config;
                            XmlNode node = config.GetConfigSection("CommunityServer/CSModules");
                            app = new CSApplication();
                            if(node != null)
                            {
                                 foreach(XmlNode n in node.ChildNodes)
                                 {
                                      if(n.NodeType != XmlNodeType.Comment)
                                     {
                                          switch(n.Name)
                                          {
                                               case "clear":
                                                    app.modules.Clear();
                                                   break;
                                               case "remove":
                                            XmlAttribute removeNameAtt = n.Attributes["name"];
                                            string removeName = removeNameAtt == null ? null : removeNameAtt.Value;
 
                                            if(!Globals.IsNullorEmpty(removeName) && app.modules.ContainsKey(removeName))
                                            {
                                                app.modules.Remove(removeName);   
                                            }
                                                   break;
                                               case "add":
                                            XmlAttribute en = n.Attributes["enabled"];
                                            if(en != null && en.Value == "false")
                                                continue;                           
                                            XmlAttribute nameAtt = n.Attributes["name"];
                                            XmlAttribute typeAtt = n.Attributes["type"];
                                                   string name = nameAtt == null ? null : nameAtt.Value;
                                                   string itype = typeAtt == null ? null : typeAtt.Value;            
                                            if(Globals.IsNullorEmpty(name))
                                            {
                                                EventLogs.Warn(string.Format("A CSModule could not be loaded. The name was not defined. Type {0}", itype), "CSModules", 654, CSContext.Current.SettingsID);
                                                continue;
                                            }
                                            if(Globals.IsNullorEmpty(itype))
                                            {
                                                EventLogs.Warn(string.Format("A CSModule ({0}) could not be loaded. No type was defined", name), "CSModules", 655, CSContext.Current.SettingsID);
                                                continue;
                                            }
                                                   Type type = Type.GetType(itype);
 
                                            if(type == null)
                                            {
                                                EventLogs.Warn(string.Format("A CSModule ({0}) could not be loaded. The type {1} does not exist", name,itype), "CSModules", 656, CSContext.Current.SettingsID);
                                                continue;
                                            }
 
                                                    ICSModule mod = Activator.CreateInstance(type) as ICSModule;
                                                   if(mod == null)
                                                   {
                                                EventLogs.Warn(string.Format("A CSModule ({0}) could not be loaded. The type {1} could not be instantiated", name,itype), "CSModules", 657, CSContext.Current.SettingsID);
                                                continue;
                                            }
                                                    mod.Init(app, n);
                                                    app.modules.Add(name,mod);
 
 
                                                   break;
 
                                          }
                                     }
                                 }
                            }
                            CacheDependency dep = new CacheDependency(null, new string[]{CSConfiguration.CacheKey});
                            CSCache.Max(key, app,dep);
                       }
 
                      
                   }
              }
              return app;
         }
以上代码通过分析"CommunityServer/CSModules"来加载需要监听事件的模块(CSModule)
                                                    ICSModule mod = Activator.CreateInstance(type) as ICSModule;
这里实例化ICSModule利用的是反射。通过此语句 还初始化模块,参与监听时间。监听事件 采用的是Add remove形式,允许事件广播机制
在获得CSModule的实例后,马上调用了其Init函数,这类函数主要是携带一个当前CSApplication的实例,并携带CommunityServer/CSModules配置当前节点的XML节点对象。通常的Inti函数应当通过如下类似代码进行事件的挂接:
public void Init(CSApplication csa, XmlNode node)
         {
              csa.UserKnown +=new CSUserEventHandler(csa_UserKnown);
         }
也就是通知CSApplication,该模块会接获其中的事件。
那么再回到CSApplication 如何管理这些事件并进行分发的呢?
在Init函数内部使用 += 来监听事件的时候,此时会将监听回调函数存储:
public event CSUserEventHandler UserKnown
         {
              add{Events.AddHandler(EventUserKnown, value);}
              remove{Events.RemoveHandler(EventUserKnown, value);}
         }
此时通过add remove 将回调函数句柄存储到哈希表中,这样就允许一个事件多个回调函数。
这样,大家可看到在CS中,事件流是通过CSApplication实例来汇聚,通过其中的事件机制分发到在Init函数中注册的多个Module,这样的分发路径就是:
 
事件源 ---》CSApplication实例 –》 CSModule1
                                          |
                                          ------------》CSModule2
|-----》CSModule3 。。。。。
 
 
这样设计的好处呢?
1、 事件的产生与事件的处理是分离的。
2、 可以做到事件的广播,多个监听器都可以处理事件;而且这种处理可以通过配置文件来实现。做到,“轻编程重配置”,还做到松耦合。

新增一个事件,有一定的布局结构参考。有利于系统的扩展扩充。 

抱歉!评论已关闭.