Nop有着完善的事件機制,在框架中也屢次用到。好比刪除刪除電子郵件時刪除指定的緩存、更新實體時,更新緩存等。這裏用到的是「生產者/消費者」模式,該模式中,定義了對象之間一對多的依賴,當一個對象改變狀態時,它的全部依賴者都會收到通知並自動更新。生產者發佈事件,消費者處理事件。緩存
一.相關接口和類:框架
1.IEventPublisher事件發佈接口。ide
2.EventPublisher實現IEventPublisher的類,主要功能包括髮布事件並通知訂閱者。函數
3.IConsumer<T>消費者(事件訂閱者)接口。this
4.ISubscriptionService訂閱者接口,解析全部的訂閱者。spa
5.SubscriptionService的具體實現。插件
二註冊事件:code
若是用戶想要偵聽事件,就須要註冊成爲消費者。消費者接口IConsumer<T>爲一個泛型接口,裏面有一個處理事件的方法。IConsumer<T>接口代碼以下:對象
/// <summary> /// 消費者 /// </summary> public interface IConsumer<T> { void HandleEvent(T eventMessage); }
在該框架中,實現IConsumer<T>接口的類不少好比Nop.Admin.Infrastructure.Cache.ModelCacheEventConsumer代碼以下:blog
public partial class ModelCacheEventConsumer : IConsumer<EntityUpdated<UrlRecord>> { public void HandleEvent(EntityUpdated<UrlRecord> eventMessage) { throw new NotImplementedException(); } #region KEY /// <summary> /// Key for widget info /// </summary> /// <remarks> /// {0} : current store ID /// {1} : widget zone /// {2} : current theme name /// </remarks> public const string WIDGET_MODEL_KEY = "NopFramework.pres.widget-{0}"; public const string WIDGET_PATTERN_KEY = "NopFramework.pres.widget"; #endregion }
「HandleEvent」爲對應的事件處理方法,能夠根據須要處理。實現了「IConsumer<T>」接口就註冊成爲了訂閱者,當有任何消息發佈時,就能真聽到對應的事件。
三.事件訂閱
事件訂閱主要就是解析哪些用戶訂閱了事件,這樣當事件發生時,才能準確的發送到指定的用戶。訂閱接口以下:
/// <summary> /// 事件訂閱服務 /// </summary> public interface ISubscriptionService { IList<IConsumer<T>> GetSubscriptions<T>(); }
該接口只有一個獲取一個方法--獲取全部註冊事件的用戶。實現該類具體以下:
/// <summary> /// 事件訂閱服務 /// </summary> public class SubscriptionService : ISubscriptionService { public IList<IConsumer<T>> GetSubscriptions<T>() { return EngineContext.Current.ResolveAll<IConsumer<T>>();// } }
四.事件發佈
事件發佈接口「IEventPublisher」。該接口只包含一個方法:
/// <summary> /// 事件發佈接口 /// </summary> public interface IEventPublisher { /// <summary> /// 事件發佈 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="eventMessage"></param> void Publish<T>(T eventMessage); }
具體的實現以下:
public class EventPublisher : IEventPublisher { private readonly ISubscriptionService _subscriptionService; /// <summary> /// 構造函數 /// </summary> /// <param name="subscriptionService"></param> public EventPublisher(ISubscriptionService subscriptionService) { this._subscriptionService = subscriptionService; } /// <summary> /// 發佈事件,通知訂閱者 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="x"></param> /// <param name="eventMessage"></param> public virtual void PublishToConsumer<T>(IConsumer<T> x,T eventMessage) { try { x.HandleEvent(eventMessage); } catch (Exception exc) { var logger= EngineContext.Current.Resolve<ILogger>(); try { logger.Error(exc.Message, exc); } catch (Exception) { } } } /// <summary> /// 根據位於其程序集中的某個類型找到一個插件描述符 /// </summary> /// <param name="providerType"></param> /// <returns></returns> protected virtual PluginDescriptor FindPlugin(Type providerType) { if (providerType == null) throw new ArgumentNullException("providerType"); if (PluginManager.ReferencedPlugins == null) return null; foreach (var plugin in PluginManager.ReferencedPlugins) { if (plugin.ReferencedAssembly == null) continue; if (plugin.ReferencedAssembly.FullName == providerType.Assembly.FullName) return plugin; } return null; } /// <summary> /// 發佈事件 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="eventMessage"></param> public virtual void Publish<T>(T eventMessage) { var subscriptions = _subscriptionService.GetSubscriptions<T>();//查找全部註冊事件的用戶 subscriptions.ToList().ForEach(x=>PublishToConsumer(x,eventMessage)); } }
先看下「Publish<T>(T eventMessage)」方法,該方法是由其餘方法好比更新或者刪除實體後調用,觸發事件。而後調用ISubscriptionService 接口的「GetSubscriptions」方法,查找全部註冊該接口的事件,以後逐條遍歷訂閱者,執行「PublishToConsumer」方法,發佈事件,通知訂閱者,具體的處理,可在「HandleEvent」實現;