一.nop事件機制簡介
應(yīng)用場景:客戶支付成功后,需要發(fā)送短信、郵件告知客戶訂單支付成功(短信、郵件由不同模塊實現(xiàn))
實現(xiàn)方法: 1.定義支付成功OrderPaidEvent事件。
2.定義短信,郵箱兩個消費者共同監(jiān)聽OrderPaidEvent事件,并實現(xiàn)相關(guān)業(yè)務(wù)。
3.當(dāng)客戶支付成功后生產(chǎn)者發(fā)送OrderPaidEvent事件。
4.消費者接收到OrderPaidEvent事件后,短信和郵箱消費者分別執(zhí)行自己的業(yè)務(wù)。
nop事件機制使用到“生產(chǎn)者/消費者”模式。生產(chǎn)者只負(fù)責(zé)發(fā)布事件,并不需要關(guān)心誰來處理,相反消費者只用來處理事件。那生產(chǎn)者和消費者是如何進行關(guān)聯(lián)的呢?nop實現(xiàn)是非常簡單的,通過泛型來定義一個事件類,如果生產(chǎn)者和消費者都使用同一個事件類,那么就關(guān)聯(lián)到一起了稱之為訂閱。負(fù)責(zé)實現(xiàn)事件機制的部分稱之為緩沖區(qū),緩沖區(qū)的作用是通過解耦的方式實現(xiàn)消息機制。生產(chǎn)者和消費者是一對多的關(guān)系。下圖簡單介紹下生產(chǎn)者消費者關(guān)系。
二.nop事件相關(guān)接口
生產(chǎn)者接口:Nop.Services.Events.IEventPublisher
消費者接口:Nop.Services.Events.IConsumer<T>
事件訂閱接口:Nop.Services.Events.ISubscriptionService
IEventPublisher接口Publish<T>(T eventMessage)方法用于發(fā)布事件(生產(chǎn)者)。
IConsumer<T>接口HandleEvent(T eventMessage)方法用于處理事件(消費者)。
兩者之間的關(guān)系由T泛型來關(guān)聯(lián),稱之為事件,簡單的說T類型相同則兩者關(guān)聯(lián)訂閱成功。
ISubscriptionService接口GetSubscriptions<T>()方法返回IList<IConsumer<T>>集合,該集合保存了消費者。
接口實現(xiàn)如下圖:
EventPublisher
1 using System.Collections.Generic; 2 using Nop.Core.Infrastructure; 3 4 namespace Nop.Services.Events 5 { 6 /// <summary> 7 /// 事件訂閱服務(wù) 8 /// </summary> 9 public class SubscriptionService : ISubscriptionService 10 { 11 /// <summary> 12 /// 獲取事件訂閱 13 /// </summary> 14 /// <typeparam name="T">Type</typeparam> 15 /// <returns>Event consumers</returns> 16 public IList<IConsumer<T>> GetSubscriptions<T>() 17 { 18 return EngineContext.Current.ResolveAll<IConsumer<T>>(); 19 } 20 } 21 } 22
二.消費者IConsermer<T>注冊
應(yīng)用啟動時Nop.Web.Framework.DependencyRegistrar中將所有實現(xiàn)IConsumer<T>接口的類注冊到ioc容器中。
通過EngineContext.Current.ResolveAll<IConsumer<T>>(),就可以獲取到某個消息(T)的訂閱了。
1 //注冊事件消費者 2 var consumers = typeFinder.FindClassesOfType(typeof(IConsumer<>)).ToList(); 3 foreach (var consumer in consumers) 4 { 5 builder.RegisterType(consumer) 6 .As(consumer.FindInterfaces((type, criteria) => 7 { 8 var isMatch = type.IsGenericType && ((Type)criteria).IsAssignableFrom(type.GetGenericTypeDefinition()); 9 return isMatch; 10 }, typeof(IConsumer<>))) 11 .InstancePerLifetimeScope(); 12 }
三.創(chuàng)建消費者
結(jié)合上邊提到的應(yīng)用場景,我們創(chuàng)建訂閱OrderPaidEvent事件來處理短信通知的消費者。
創(chuàng)建OrderPaidSMSEventConsumer類
1 using System; 2 using Nop.Core; 3 using Nop.Core.Domain.Orders; 4 using Nop.Core.Plugins; 5 using Nop.Services.Events; 6 using Nop.Services.Orders; 7 8 namespace Nop.Plugin.SMS 9 { 10 public class OrderPaidSMSEventConsumer : IConsumer<OrderPaidEvent> 11 { 12 13 private readonly IOrderService _orderService; 14 15 public OrderPaidSMSEventConsumer( 16 IOrderService orderService, 17 IStoreContext storeContext) 18 { 19 this._orderService = orderService; 20 this._storeContext = storeContext; 21 } 22 23 /// <summary> 24 /// 事件處理. 25 /// </summary> 26 /// <param name="eventMessage">The event message.</param> 27 public void HandleEvent(OrderPaidEvent eventMessage) 28 { 29 30 var order = eventMessage.Order;//獲取訂單 31 32 //發(fā)送短息通知代碼 33 //.................... 34 } 35 } 36 }
OrderPaidSMSEventConsumer類繼承 IConsumer<OrderPaidEvent>,OrderPaidEvent就是事件類,維護生產(chǎn)者與消費者之間的訂閱關(guān)系。事件類名稱可以自定義,代表了一個事件。
接下來我們再創(chuàng)建一個郵件處理的消費者OrderPaidEmailEventConsumer類,同樣繼承了ICnsumer<OrderPaidEvent>,說明我們訂閱的是也是OrderPaidEvent事件。
1 using System; 2 using Nop.Core; 3 using Nop.Core.Domain.Orders; 4 using Nop.Core.Plugins; 5 using Nop.Services.Events; 6 using Nop.Services.Orders; 7 8 namespace Nop.Plugin.Email 9 { 10 public class OrderPaidEmailEventConsumer : IConsumer<OrderPaidEvent> 11 { 12 13 private readonly IOrderService _orderService; 14 private readonly IStoreContext _storeContext; 15 16 public OrderPaidEmailEventConsumer( 17 IOrderService orderService, 18 IStoreContext storeContext) 19 { 20 21 this._orderService = orderService; 22 this._storeContext = storeContext; 23 } 24 25 /// <summary> 26 /// 郵件處理 27 /// </summary> 28 /// <param name="eventMessage">The event message.</param> 29 public void HandleEvent(OrderPaidEvent eventMessage) 30 { 31 32 33 var order = eventMessage.Order; 34 35 //發(fā)送郵件通知客戶 36 //............................ 37 } 38 } 39 }
四.生產(chǎn)消息
我們已經(jīng)創(chuàng)建了兩個訂閱了OrderPaidEvent事件的消費者,現(xiàn)在我們看看當(dāng)客戶支付完成時我們是如何通知消費者的。
Nop.Services.OrderProcessingService類中
_eventPublisher.Publish(new OrderPaidEvent(order))方法發(fā)送了OrderPaidEvent事件。這時候上邊訂閱OrderPaidEvent事件的消費(短信、郵件)就會處理消息了。
五.nop中常用的事件整理
消費者,主要還是處理緩存
Nop.Web.Infrastructure.Cache.ModelCacheEventConsumer:前臺模型相關(guān)
Nop.Admin.Infrastructure.Cache.ModelCacheEventConsumer:后臺模型相關(guān)
Nop.Services.Discounts.Cache.DiscountEventConsumer:折扣相關(guān)
Nop.Services.Catalog.Cache.PriceCacheEventConsumer:價格相關(guān)
Nop.Services.Customers.Cache.CustomerCacheEventConsumer:密碼修改
生產(chǎn)者,下圖總結(jié)了nop 3.9 源碼中自帶的事件及所在的類,大部分是未實現(xiàn)對應(yīng)的消費者。
nop只是在相關(guān)的地方留下事件位置,方便我們二次開發(fā)的時候進行擴展。
六.總結(jié)
1.生產(chǎn)者需要繼承IEventPublisher接口。
2.消費者需要繼承IConsumer<T>接口。
3.消費者通過事件類訂閱到生產(chǎn)者,訂閱實現(xiàn)參見ISubscriptionService接口。
nop事件機制實現(xiàn)很簡單,有興趣的朋友可以用RabbitMQ進行消息的擴展。
文中有錯誤的理解和不正確的觀點,請留言,一起交流共同進步。
本文地址:http://www.cnblogs.com/yaoshangjin/p/7234522.html
本文為大波浪原創(chuàng)、轉(zhuǎn)載請注明出處。
如果您認(rèn)為這篇文章還不錯或者有所收獲,可以點擊下方的【關(guān)注】按鈕,因為你的支持是我繼續(xù)寫作,分享的最大動力!
作者:大波浪
來源:http://www.cnblogs.com/yaoshangjin/
聲明: 本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。如果您發(fā)現(xiàn)博客中出現(xiàn)了錯誤,或者有更好的建議、想法,請及時與我聯(lián)系??!如果想找我私下交流,可以私信或者加我QQ。
http://www.cnblogs.com/yaoshangjin/p/7234522.html