結合DI,實現發佈者與訂閱者的解耦,屬於本次事務的對象主體不該定義爲訂閱者,由於訂閱者不該與發佈者產生任何關聯html
1、發佈者訂閱者模式設計模式
發佈者發出一個事件主題,一個或多個訂閱者接收這個事件,中間經過事件總線通信(消息隊列),而且發佈者與訂閱者這二者間是無狀態的,根據產品實際場景須要,能夠本身實現單機單點的發佈訂閱,也可選擇使用目前流行的分佈式消息中間件:微信
RabbitMQ、ActiveMQ、RocketMQ、kafka等app
2、觀察者與訂閱者的區別框架
觀察者與業務主體是耦合的,而且是即時通知的;訂閱者與業務主體徹底解耦,只經過中間的信息通道通知,互相不知道對方的存在,能夠是同步也能夠是異步異步
3、具體實現分佈式
本文主要講解單點模式,有須要隨時能夠擴展爲分佈式方案ide
發佈者接口:post
1 namespace Xms.Event.Abstractions 2 { 3 /// <summary> 4 /// 事件發佈接口 5 /// </summary> 6 public interface IEventPublisher 7 { 8 /// <summary> 9 /// 發佈事件 10 /// </summary> 11 /// <typeparam name="TEvent">事件類型</typeparam> 12 /// <param name="e"></param> 13 void Publish<TEvent>(TEvent e); 14 } 15 }
發佈者實現:url
1 using System; 2 using System.Linq; 3 using Xms.Event.Abstractions; 4 using Xms.Infrastructure.Inject; 5 using Xms.Logging.AppLog; 6 7 namespace Xms.Event 8 { 9 /// <summary> 10 /// 事件發佈者 11 /// </summary> 12 public class EventPublisher : IEventPublisher 13 { 14 private readonly ILogService _logService; 15 private readonly IServiceResolver _serviceResolver; 16 17 public EventPublisher(ILogService logService 18 , IServiceResolver serviceResolver) 19 { 20 _logService = logService; 21 _serviceResolver = serviceResolver; 22 } 23 24 #region Methods 25 26 /// <summary> 27 /// 發佈事件 28 /// </summary> 29 /// <typeparam name="TEvent">事件類</typeparam> 30 /// <param name="e">事件對象</param> 31 public virtual void Publish<TEvent>(TEvent e) 32 { 33 //獲取全部事件接收者 34 var consumers = _serviceResolver.GetAll<IConsumer<TEvent>>().ToList(); 35 foreach (var consumer in consumers) 36 { 37 try 38 { 39 //處理事件 40 consumer.HandleEvent(e); 41 } 42 catch (Exception exception) 43 { 44 _logService.Error(exception); 45 } 46 } 47 } 48 49 #endregion Methods 50 } 51 }
訂閱(消費)者接口:
1 namespace Xms.Event.Abstractions 2 { 3 /// <summary> 4 /// 事件接收接口 5 /// </summary> 6 /// <typeparam name="T"></typeparam> 7 public interface IConsumer<T> 8 { 9 /// <summary> 10 /// 處理事件 11 /// </summary> 12 /// <param name="eventMessage">事件</param> 13 void HandleEvent(T eventMessage); 14 } 15 }
事件(消息):
這裏只給出一個做爲示例,實際上通常會有記錄的:「建立」、「修改」、「刪除」,流程相關的:「發起審批」、「審批經過」、「審批完成」等等
1 namespace Xms.Flow.Core.Events 2 { 3 /// <summary> 4 /// 工做流啓動後事件 5 /// </summary> 6 public class WorkFlowStartedEvent 7 { 8 public WorkFlowStartUpContext Context { get; set; } 9 public WorkFlowExecutionResult Result { get; set; } 10 } 11 }
服務註冊:
詳細實現回看.netcore之DI批量注入(支持泛型)
1 using Microsoft.Extensions.Configuration; 2 using Microsoft.Extensions.DependencyInjection; 3 using Xms.Core; 4 using Xms.Infrastructure.Inject; 5 6 namespace Xms.Event 7 { 8 /// <summary> 9 /// 事件模塊服務註冊 10 /// </summary> 11 public class ServiceRegistrar : IServiceRegistrar 12 { 13 public int Order => 1; 14 15 public void Add(IServiceCollection services, IConfiguration configuration) 16 { 17 //event publisher 18 services.AddScoped<Event.Abstractions.IEventPublisher, Event.EventPublisher>(); 19 //event consumers 20 services.RegisterScope(typeof(Event.Abstractions.IConsumer<>)); 21 } 22 } 23 }
4、應用場景
好比在工做流啓動審批後發送通知
1 using System.Collections.Generic; 2 using Xms.Context; 3 using Xms.Event.Abstractions; 4 using Xms.Flow.Core.Events; 5 using Xms.Infrastructure.Utility; 6 using Xms.Localization.Abstractions; 7 using Xms.Notify.Abstractions; 8 using Xms.Notify.Internal; 9 10 namespace Xms.EventConsumers.Notify 11 { 12 /// <summary> 13 /// 工做流啓動審批後發送通知 14 /// </summary> 15 public class WorkflowStartedNotify : IConsumer<WorkFlowStartedEvent> 16 { 17 private readonly IAppContext _appContext; 18 private readonly ILocalizedTextProvider _loc; 19 private readonly IEnumerable<INotify> _notifies; 20 21 public WorkflowStartedNotify(IAppContext appContext 22 , IEnumerable<INotify> notifies) 23 { 24 _appContext = appContext; 25 _loc = _appContext.GetFeature<ILocalizedTextProvider>(); 26 _notifies = notifies; 27 } 28 public void HandleEvent(WorkFlowStartedEvent eventMessage) 29 { 30 //當前節點處理人 31 foreach (var handlerId in eventMessage.Result.NextHandlerId) 32 { 33 //通知方式:微信、短信、郵件、系統消息等 34 var msg = _loc["workflow_newtasknotify"].FormatWith(eventMessage.Context.EntityMetaData.LocalizedName); 35 //發送消息 36 foreach (var notifier in _notifies) 37 { 38 notifier.Send(new InternalNotifyBody() 39 { 40 TypeCode = 2 41 , 42 Subject = msg 43 , 44 Content = "到你審批了,快到碗裏來" 45 , 46 ToUserId = handlerId 47 , 48 LinkTo = "/entity/create?entityid=" + eventMessage.Context.EntityMetaData.EntityId + "&recordid=" + eventMessage.Context.ObjectId 49 }); 50 } 51 } 52 } 53 } 54 }
4、總結
前面講解了訂閱者模式的基本概念及與觀察者的區別,後面展現了具體實現及實際應用場景,你們記住一點就行,這些設計模式最終都是爲了達到解藕的目的,要查看完整代碼,請回到這一章