.netcore利用DI实现订阅者模式 - xms
结合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的更多相关文章
- .netcore之DI批量注入(支持泛型) - xms
一旦系统内模块比较多,按DI标准方法去逐个硬敲AddScoped/AddSingleton/AddTransient缺乏灵活性且效率低下,所以批量注入提供了很大的便捷性,特别是对于泛型的服务类,下面介 ...
- 利用DI实现级联删除 - xms跨平台基础框架 - 基于.netcore
一.引言 所谓级联删除是指删除一条记录后,附带关联记录也一起删除,比如删除客户后,联系人也一起删除: 以往我们会依赖于数据库表的外键约束,但存在着明显的问题,增加数据库压力.提示不友好.职责越界.事务 ...
- AngularJS的简单订阅发布模式例子
控制器之间的交互方式广播 broadcast, 发射 emit 事件 类似于 js中的事件 , 可以自己定义事件 向上传递直到 document 在AngularJs中 向上传递直到 rootScop ...
- js设计模式之代理模式以及订阅发布模式
为啥将两种模式放在一起呢?因为这样文章比较长啊. 写博客的目的我觉得首要目的是整理自己的知识点,进而优化个人所得知识体系.知识成为个人的知识,就在于能够用自己的话表达同一种意义. 本文是设计模式系列文 ...
- RabbitMQ (五) 订阅者模式之分发模式 ( fanout )
前面讲到了简单队列和工作队列. 这两种队列有个非常明显的缺点 : 生产者发送的消息,只能进入到一个队列. 消息只能进入到一个队列就意味着消息只能被一个消费者消费. 尽管工作队列模式中,一个队列中的消息 ...
- C#事件支持发布者/订阅者模式(观察者模式)
C#事件支持发布者/订阅者模式,发布者将事件通知给订阅者,而订阅者在事件发生时调用已经注册好的事件处理函数. public delegate void delUpdate(); //委 ...
- Android 订阅-发布者模式-详解
1.概念简述 Android 简称观察者模式, GoF说道:Observer模式的意图是“定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”. 有 ...
- Publisher/Subscriber 订阅-发布模式
Publisher/Subscriber 订阅-发布模式 本博后续将陆续整理这些年做的一些预研demo,及一些前沿技术的研究,与大家共研技术,共同进步. 关于发布订阅有很多种实现方式,下面主要介绍WC ...
- 设计模式---订阅发布模式(Subscribe/Publish)
设计模式---订阅发布模式(Subscribe/Publish) 订阅发布模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象.这个主题对象在自身状态变化时,会通知所有订阅者对象,使 ...
随机推荐
- 从单片机到操作系统⑦——深入了解FreeRTOS的延时机制
>没研究过操作系统的源码都不算学过操作系统 # FreeRTOS 时间管理 时间管理包括两个方面:系统节拍以及任务延时管理. ## 系统节拍: 在前面的文章也讲得很多,想要系统正常运行,那么时钟 ...
- HashTable、Dictionary、ConcurrentDictionary三者区别
转载自https://blog.csdn.net/yinghuolsx/article/details/72952857 1.HashTable HashTable表示键/值对的集合.在.NET Fr ...
- Python的字符串编码
本文用实验详细地演示了Python2和Python3在字符串编码上的区别. 在Python2中,字符串字面量对应于8位的字符或面向字节编码的字节字面量.这些字符串的一个重要限制是它们无法完全地支持国际 ...
- POJ2828 Buy Tickets 树状数组
Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get ...
- spring boot 2.x文件路径映射问题汇总
当我们在运行可执行的java jar包的时候,我们肯定改变不了jar里面的内容,因此文件上传路径就成了我们必须考虑的一点问题,我们不能往直接这个jar包里面写文件,那么只能写在jar包外面,但是写到j ...
- VS2017-Linux项目-使用第三方库如何配置
1.虚拟机Ubuntu 16.04,安装第三方库,perftools::tcmalloc. 2.Win10下vs2017创建linux项目. 3.项目>>属性>>VC++ 目录 ...
- 如何定制 Spring Boot 的 Banner?
相信用过 Spring Boot 的朋友们一定在启动日志中见过类似如下的内容,比如在启动 Spring Boot 时,控制台默认会打印 Spring Boot Logo 以及版本信息,这是 Sprin ...
- 玩转PubSubClient MQTT库
1.前言 在ESP8266学习系列中,博主一直使用HTTP协议.HTTP连接属于短连接,而在物联网应用中,广泛应用的却是MQTT协议.所以,本篇我们将学习Arduino平台上的MQTT实现库 ...
- nsq (三) 消息传输的可靠性和持久化[一]
上两篇帖子主要说了一下nsq的拓扑结构,如何进行故障处理和横向扩展,保证了客户端和服务端的长连接,连接保持了,就要传输数据了,nsq如何保证消息被订阅者消费,如何保证消息不丢失,就是今天要阐述的内容. ...
- java Int数据工具类
1.在使用tcp协议传输数据时,使用到的 Int 数据的工具类方法 //将 Int 数据转换成字节数组 public static byte[] intToByteArray(int data){ b ...