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、 可以做到事件的廣播,多個監聽器都可以處理事件;而且這種處理可以通過設定檔來實現。做到,“輕編程重配置”,還做到松耦合。
新增一個事件,有一定的布局結構參考。有利於系統的擴充擴充。