zoukankan      html  css  js  c++  java
  • Nopcommerce 之事件机制

    Nop有着完善的事件机制,在框架中也多次用到。比如删除删除电子邮件时删除指定的缓存、更新实体时,更新缓存等。这里用到的是“生产者/消费者”模式,该模式中,定义了对象之间一对多的依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。生产者发布事件,消费者处理事件。

    一.相关接口和类:

    1.IEventPublisher事件发布接口。

    2.EventPublisher实现IEventPublisher的类,主要功能包括发布事件并通知订阅者。

    3.IConsumer<T>消费者(事件订阅者)接口。

    4.ISubscriptionService订阅者接口,解析所有的订阅者。

    5.SubscriptionService的具体实现。

    二注册事件:

       如果用户想要侦听事件,就需要注册成为消费者。消费者接口IConsumer<T>为一个泛型接口,里面有一个处理事件的方法。IConsumer<T>接口代码如下:

    /// <summary>
        /// 消费者
        /// </summary>
        public interface IConsumer<T>
        {
            void HandleEvent(T eventMessage);
        }

    在该框架中,实现IConsumer<T>接口的类很多比如Nop.Admin.Infrastructure.Cache.ModelCacheEventConsumer代码如下:

    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”实现;

  • 相关阅读:
    知识小罐头05(tomcat8请求源码分析 上)
    知识小罐头04(idea+maven+部署war包到tomcat 下)
    知识小罐头03(idea+maven+部署war包到tomcat 上)
    带着新人学springboot的应用13(springboot+热部署)
    带着新人学springboot的应用12(springboot+Dubbo+Zookeeper 下)
    带着新人学springboot的应用11(springboot+Dubbo+Zookeeper 上)
    带着新人学springboot的应用10(springboot+定时任务+发邮件)
    带着新人学springboot的应用09(springboot+异步任务)
    带着新人学springboot的应用08(springboot+jpa的整合)
    windows最简单的局部截图工具
  • 原文地址:https://www.cnblogs.com/SecondSun/p/7590781.html
Copyright © 2011-2022 走看看