结合DI,实现发布者与订阅者的解耦,属于本次事务的对象主体不应定义为订阅者,因为订阅者不应与发布者产生任何关联

一、发布者订阅者模式

发布者发出一个事件主题,一个或多个订阅者接收这个事件,中间通过事件总线通讯(消息队列),并且发布者与订阅者这两者间是无状态的,根据产品实际场景需要,可以自己实现单机单点的发布订阅,也可选择使用目前流行的分布式消息中间件:

RabbitMQ、ActiveMQ、RocketMQ、kafka等

二、观察者与订阅者的区别

观察者与业务主体是耦合的,并且是即时通知的;订阅者与业务主体完全解耦,只通过中间的信息通道通知,互相不知道对方的存在,可以是同步也可以是异步

三、具体实现

本文主要讲解单点模式,有需要随时可以扩展为分布式方案

发布者接口:

 namespace Xms.Event.Abstractions
{
/// <summary>
/// 事件发布接口
/// </summary>
public interface IEventPublisher
{
/// <summary>
/// 发布事件
/// </summary>
/// <typeparam name="TEvent">事件类型</typeparam>
/// <param name="e"></param>
void Publish<TEvent>(TEvent e);
}
}

发布者实现:

 using System;
using System.Linq;
using Xms.Event.Abstractions;
using Xms.Infrastructure.Inject;
using Xms.Logging.AppLog; namespace Xms.Event
{
/// <summary>
/// 事件发布者
/// </summary>
public class EventPublisher : IEventPublisher
{
private readonly ILogService _logService;
private readonly IServiceResolver _serviceResolver; public EventPublisher(ILogService logService
, IServiceResolver serviceResolver)
{
_logService = logService;
_serviceResolver = serviceResolver;
} #region Methods /// <summary>
/// 发布事件
/// </summary>
/// <typeparam name="TEvent">事件类</typeparam>
/// <param name="e">事件对象</param>
public virtual void Publish<TEvent>(TEvent e)
{
//获取所有事件接收者
var consumers = _serviceResolver.GetAll<IConsumer<TEvent>>().ToList();
foreach (var consumer in consumers)
{
try
{
//处理事件
consumer.HandleEvent(e);
}
catch (Exception exception)
{
_logService.Error(exception);
}
}
} #endregion Methods
}
}

订阅(消费)者接口:

 namespace Xms.Event.Abstractions
{
/// <summary>
/// 事件接收接口
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IConsumer<T>
{
/// <summary>
/// 处理事件
/// </summary>
/// <param name="eventMessage">事件</param>
void HandleEvent(T eventMessage);
}
}

事件(消息):

这里只给出一个作为示例,实际上一般会有记录的:“创建”、“修改”、“删除”,流程相关的:“发起审批”、“审批通过”、“审批完成”等等

 namespace Xms.Flow.Core.Events
{
/// <summary>
/// 工作流启动后事件
/// </summary>
public class WorkFlowStartedEvent
{
public WorkFlowStartUpContext Context { get; set; }
public WorkFlowExecutionResult Result { get; set; }
}
}

服务注册:

详细实现回看.netcore之DI批量注入(支持泛型)

 using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Xms.Core;
using Xms.Infrastructure.Inject; namespace Xms.Event
{
/// <summary>
/// 事件模块服务注册
/// </summary>
public class ServiceRegistrar : IServiceRegistrar
{
public int Order => ; public void Add(IServiceCollection services, IConfiguration configuration)
{
//event publisher
services.AddScoped<Event.Abstractions.IEventPublisher, Event.EventPublisher>();
//event consumers
services.RegisterScope(typeof(Event.Abstractions.IConsumer<>));
}
}
}

四、应用场景

比如在工作流启动审批后发送通知

 using System.Collections.Generic;
using Xms.Context;
using Xms.Event.Abstractions;
using Xms.Flow.Core.Events;
using Xms.Infrastructure.Utility;
using Xms.Localization.Abstractions;
using Xms.Notify.Abstractions;
using Xms.Notify.Internal; namespace Xms.EventConsumers.Notify
{
/// <summary>
/// 工作流启动审批后发送通知
/// </summary>
public class WorkflowStartedNotify : IConsumer<WorkFlowStartedEvent>
{
private readonly IAppContext _appContext;
private readonly ILocalizedTextProvider _loc;
private readonly IEnumerable<INotify> _notifies; public WorkflowStartedNotify(IAppContext appContext
, IEnumerable<INotify> notifies)
{
_appContext = appContext;
_loc = _appContext.GetFeature<ILocalizedTextProvider>();
_notifies = notifies;
}
public void HandleEvent(WorkFlowStartedEvent eventMessage)
{
//当前节点处理人
foreach (var handlerId in eventMessage.Result.NextHandlerId)
{
//通知方式:微信、短信、邮件、系统消息等
var msg = _loc["workflow_newtasknotify"].FormatWith(eventMessage.Context.EntityMetaData.LocalizedName);
//发送消息
foreach (var notifier in _notifies)
{
notifier.Send(new InternalNotifyBody()
{
TypeCode =
,
Subject = msg
,
Content = "到你审批了,快到碗里来"
,
ToUserId = handlerId
,
LinkTo = "/entity/create?entityid=" + eventMessage.Context.EntityMetaData.EntityId + "&recordid=" + eventMessage.Context.ObjectId
});
}
}
}
}
}

四、总结

前面讲解了订阅者模式的基本概念及与观察者的区别,后面展示了具体实现及实际应用场景,大家记住一点就行,这些设计模式最终都是为了达到解藕的目的,要查看完整代码,请回到这一章

xms跨平台基础框架 - 基于.netcore

.netcore利用DI实现订阅者模式 - xms的更多相关文章

  1. .netcore之DI批量注入(支持泛型) - xms

    一旦系统内模块比较多,按DI标准方法去逐个硬敲AddScoped/AddSingleton/AddTransient缺乏灵活性且效率低下,所以批量注入提供了很大的便捷性,特别是对于泛型的服务类,下面介 ...

  2. 利用DI实现级联删除 - xms跨平台基础框架 - 基于.netcore

    一.引言 所谓级联删除是指删除一条记录后,附带关联记录也一起删除,比如删除客户后,联系人也一起删除: 以往我们会依赖于数据库表的外键约束,但存在着明显的问题,增加数据库压力.提示不友好.职责越界.事务 ...

  3. AngularJS的简单订阅发布模式例子

    控制器之间的交互方式广播 broadcast, 发射 emit 事件 类似于 js中的事件 , 可以自己定义事件 向上传递直到 document 在AngularJs中 向上传递直到 rootScop ...

  4. js设计模式之代理模式以及订阅发布模式

    为啥将两种模式放在一起呢?因为这样文章比较长啊. 写博客的目的我觉得首要目的是整理自己的知识点,进而优化个人所得知识体系.知识成为个人的知识,就在于能够用自己的话表达同一种意义. 本文是设计模式系列文 ...

  5. RabbitMQ (五) 订阅者模式之分发模式 ( fanout )

    前面讲到了简单队列和工作队列. 这两种队列有个非常明显的缺点 : 生产者发送的消息,只能进入到一个队列. 消息只能进入到一个队列就意味着消息只能被一个消费者消费. 尽管工作队列模式中,一个队列中的消息 ...

  6. C#事件支持发布者/订阅者模式(观察者模式)

    C#事件支持发布者/订阅者模式,发布者将事件通知给订阅者,而订阅者在事件发生时调用已经注册好的事件处理函数.        public delegate void delUpdate();  //委 ...

  7. Android 订阅-发布者模式-详解

    1.概念简述 Android 简称观察者模式, GoF说道:Observer模式的意图是“定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”. 有 ...

  8. Publisher/Subscriber 订阅-发布模式

    Publisher/Subscriber 订阅-发布模式 本博后续将陆续整理这些年做的一些预研demo,及一些前沿技术的研究,与大家共研技术,共同进步. 关于发布订阅有很多种实现方式,下面主要介绍WC ...

  9. 设计模式---订阅发布模式(Subscribe/Publish)

    设计模式---订阅发布模式(Subscribe/Publish) 订阅发布模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象.这个主题对象在自身状态变化时,会通知所有订阅者对象,使 ...

随机推荐

  1. SQL SERVER 还原误操作导致还原无法停止,处理办法

    昨天遇到运行库不知道单位哪个小伙子,把数据库还原了,导致单位业务全部瘫痪,主数据库一直显示正在还原,真的是不敢动,经过多方寻找,找到此脚本-------------------------数据库还原日 ...

  2. 为什么不同命名空间的docker容器可以相互通信?

    一.什么是容器网络栈 所谓容器能看见的"网络栈",被隔离在自己的Network Namespace当中 1.网卡(network interface) 2.回环设备(loopbac ...

  3. ES三节点重启后报错no known master node

    问题 一直在研究ES的监控怎么做,想偷点懒,不去通过API获取然后计算,就想找个现成的插件或者监控软件,只要装个agent就可以,然后就找到了x-pack,插件装好了之后,需要重启ES集群,线上的ES ...

  4. Centos 7.2天兔(Lepus 3.8)数据库监控系统部署

    天兔(Lepus 3.8)数据库监控系统部署 转载自:https://blog.csdn.net/m0_38039437/article/details/79613260 一.安装LAMP基础环境 首 ...

  5. 蓝牙TWS耳机IBRT的原理初分析

    最近在倒腾TWS对耳的一些东西,看到一些源码,发现一个新概念,IBRT没有搞清楚,抱着吾将上下而求索的态度,详细看了一些代码,查了一些资料,还是发现了不少有价值的信息的.至少,我突然感觉自己懂了一些什 ...

  6. 就个人银行账户管理程序谈谈C++和Java的异同

    4_9 同: Java和C++都是面向对象的语言.都有数据成员,方法,访问权限的概念. 异: 访问权限上,非private时Java的默认访问权限是包.而C++的默认访问权限是private.Java ...

  7. 基于华为物联网IOT的应用开发 --- 基于.net 的SDK封装

    最近,物联网的概念比较热门,一大批厂商抢着占领物联网的高低,包括有华为物联网.阿里云物联网.腾讯物联网.AWS物联网等等,无法一一列举,一般物联网包含设备侧开发.平台侧开发.应用侧开发,三个部分构成了 ...

  8. 生产环境中利用软链接避免"rm -rf /"的方法

      1.将系统中的rm二进制文件重命名为rm_real:2.编写脚本rm_shell,rm_shell中主要包含以下内容:    2.1)路径转换模块,用于将rm_shell参数中的路径转换为绝对路径 ...

  9. ESP8266开发之旅 进阶篇⑤ 代码规范 —— 像写文章一样优美

    1.前言     之前,一直在跟大伙分享怎么去玩蓝牙模块,怎么去玩wifi模块,怎么去玩json,然后有很多小伙伴就留言各种问题或者说直接怼他的代码过来让我看,然后我就一脸懵逼(代码中到处各种abcd ...

  10. ESP8266开发之旅 基础篇④ ESP8266与EEPROM

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...