【微服务】02-集成事件与MediatR

news2025/3/2 2:07:31

文章目录

    • 1.集成事件
      • 1.1 定义
      • 1.2 集成事件工作原理
      • 1.3 总结
    • 2.使用RabbitMQ来实现EventBus
      • 2.1 RabbitMQ安装
      • 2.2 CAP框架实现RabbitMQ
        • 2.2.1 CAP框架实现架构
        • 2.2.2 CAP框架实现原理
    • 3.MediatR
      • 3.1 使用Mediator实现命令查询职责分离模式(CQRS)
        • 3.1.1 核心对象
      • 3.2 处理领域事件
        • 3.2.1 核心对象

1.集成事件

1.1 定义

集成事件目的是为了实现系统的集成,主要是用来在系统多个微服务之间相互传递事件,实现方式有两种

  • 发布、订阅通过EventBus方式
  • 通过观察者模式,由观察者将事件发给关注事件的人

1.2 集成事件工作原理

在这里插入图片描述

// 定义集成事件,命名:事件名称+IntergationEvent
public class OrderCreateIntergationEvent
{
	public OrderCreatedIntergrationEvent(long orderId) => OrderId = orderId;
	public long OrderId {get;}
}


// 发布
public class OrderCreateDomainEventHandler : IDomainEventHandler<OrderCreateDomainEvent>
{
	// 发送集成事件的接口框架
	ICapPublisher _capPublisher;
	public OrderCreateDomainEventHandler(ICapPublisher capPublisher)
	{
		_capPublisher = capPublisher;
	}
	
	public async Task Handle(OrderCreatedDomainEvent notification,CancellationToken cancelationToken)
	{
	// 将名称为 "OrderCreated"的集成事件发送出去
		await _capPublisher.PublishAsync("OrderCreated",new OrderCreatedIntergrationEvent(notification.Order.Id))
	}
}

// 订阅服务
public class SubscriberService : ISubscriberService,ICapSubscribe
{
	IMediator _mediator;
	public SubscriberService(IMediator mediator)
	{
		_mediator = mediator;
	}
	
	[CapSubscribe("OrderPaymentSuccessed")]
	public void OrderPaymentSuccessed(OrderPaymentSuccessedIntergrationEvent envent)
	{
		// TODO...
	}

}

1.3 总结

  • 集成事件是跨服务的领域事件
  • 集成事件一般由领域事件驱动触发
  • 不通过事务来处理集成事件(实现最终一致性)
  • 仅在必要的情况下定义和使用集成事件

2.使用RabbitMQ来实现EventBus

2.1 RabbitMQ安装

进入RabbitMQ网站下载
RabbitMQ下载地址

2.2 CAP框架实现RabbitMQ

2.2.1 CAP框架实现架构

在这里插入图片描述

CAP框架实际是实现了OutBox的设计模式
OutBox设计模式是在每一个微服务中,比如微服务A的数据库A中建立两张表。一张publish事件表和一张receive事件表,这两张事件表用来记录微服务A发出和接收到的事件。当需要发出事件时,会把事件的存储逻辑和业务逻辑的事务合并,在同一个事务里提交,也就意味着当业务逻辑提交成功时,事件表里面的事件是一定存在的,它是与业务逻辑的事务是强绑定的,这就保证了所发出的事件是与业务逻辑一致的。接下来就是由组件负责将事件表中的事件全部发送到EventBus中,比如RabbitMQ消息队列中,由接受方订阅。
对于订阅事件,设计模式是同理。当应用程序从消息队列中获取到消息时,就会将这些消息持久化到数据库中的receive事件表中,这样就可以在本地进行事件的处理、失败重试等操作,这都是由CAP框架来完成。

// 演示代码
private IDbContextTransaction _currentTransaction;

public Task<IDbContextTransaction> BeginTransactionAsync()
{
	if(_currentTransaction == null) return null;
	// 将业务存储放在同一个事务中,使得事务提交或回滚时,事件与业务逻辑的存取都是一致的
	_currentTransaction = DataBase.BeginTransaction(_capBus,autoCommit:false);
	return Task.FromResult(_currentTransaction);
}

// 服务配置
public static IServiceCollection AddEventBus(this IServiceCollection services,IConfiguration configuration)
{
	services.AddTransient<ISubscriberService,SubscriberService>();
	services.AddCap(options =>
	{
		// 基于DomainContext实现EventBus
		options.UseEntityFramework<DomainContext>();
		// 使用RabbitMQ作为消息队列的存储
		options.UseRabbitMQ(options =>
		{
			// RabbitMQ配置
			configuration.GetSection("RabbitMQ").Bind(options);
		});
	};
	return services;
}

2.2.2 CAP框架实现原理

  • 事件表
  • 事务控制

3.MediatR

3.1 使用Mediator实现命令查询职责分离模式(CQRS)

3.1.1 核心对象

  • IMediator
  • IRequest、IRequest< T>
  • IRequestHandler< in TRquest,TResponse>
async static Task Main(string[] args)
{
	var services = new ServiceCollection();
	services.AddMediatR(typeof(Program).Assembly);
	var serviceProvider = services.BuildServiceProvider();
	var mediator = serviceProvider.GetService<IMediator>();
	await mediator.Send(new MyCommand{CommandName= "cmd01"});
}

class MyCommand : IRequest<long>
{
	public string CommandName {get;set;}
}

// 命令处理器定义
class MyCommandHandler : IRequestHandler<MyCommand,long>
{
	public Task<long> Handle(MyCommand request,CancellationToken cancelationToken)
	{
		ConsoleWriteLine($@"MyCommandHandler 执行命令{request.CommandName}");
		return Task.FromResult(10L);
	}
}

通过中介者模式(MediatoR),可以将命令的构造和命令的处理分离开

3.2 处理领域事件

3.2.1 核心对象

  • IMediator
  • INotification
  • INotificationHandler< in TNotification>

async static Task Main(string[] args)
{
	var services = new ServiceCollection();
	services.AddMediatR(typeof(Program).Assembly);
	var serviceProvider = services.BuildServiceProvider();
	var mediator = serviceProvider.GetService<IMediator>();
	//
	await mediator.Publish(new MyEvent{EventName= "Event01"});
	Console.WriteLine("Hello World");
}


class MyEvent : INotification
{
	public string EventName {get;set;}
}

internal class MyEventHandler : INotificationHandler<MyEvent>
{
	public Task Handle(MyEvent notification,CancellationToken cancelationToken)
	{
		Console.WriteLine($"MyEventHandle执行:{notification.EventName}");
		return Task.CompletedTask;
	}
}

internal class MyEventHandler2 : INotificationHandler<MyEvent>
{
	public Task Handle(MyEvent notification,CancellationToken cancellationToken)
	{
		Console.WriteLine($"MyEventHandle2执行:{notification.EventName}");
		return Task.CompletedTask;
	}
}

INotification可以注册多个,是一对多的关系,借助此我们可以对领域事件定义多个处理器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/914862.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Tomcat线程池梳理

Tomcat梳理 文章目录 Tomcat梳理1.问题2.监控tomcat线程池springboot1.xspringboot2.x转为json格式打印输出 3.SpringBoot内置线程解析测试controlleryaml配置可知ThreadPoolExecutor有如下五种线程池状态。线程池监控指标并发测试并发请求数 < Tomcat最大线程数20并发请求数…

AcWing算法基础课第四讲动态规划(2): 线性DP、区间DP

文章目录 &#xff08;1&#xff09;线性DP898. 数字三角形895. 最长上升子序列897. 最长公共子序列 &#xff08;2) 区间DP282. 石子合并区间 DP 常用模版 &#xff08;1&#xff09;线性DP 898. 数字三角形 题目链接 给定一个如下图所示的数字三角形&#xff0c;从顶部出发…

蒙蒂卡洛与圣杯:二次更快的模拟

一、说明 针对不确知的&#xff0c;或者是 混沌问题&#xff0c;如果存在解决&#xff0c;什么方法最有效&#xff1f;本文针对蒙特卡洛法展开讨论。 你有没有试过把一个糟糕的糖果包装纸扔进垃圾桶&#xff0c;即使你把它正好放在垃圾箱上方&#xff0c;皱巴巴的塑料也很可能会…

【AIGC】AI工具合集人脸动漫化,老照片修复和视频补帧工具

Paper2GUI: 一款面向普通人的 AI 桌面 APP 工具箱&#xff0c;免安装即开即用&#xff0c;已支持 40AI 模型&#xff0c;内容涵盖 AI 绘画、语音合成、视频补帧、视频超分、目标检测、图片风格化、OCR 识别等领域。支持 Windows、Mac、Linux 系统。 小白兔AI 3.0版起永久免费A…

【Git Bash】简明从零教学

目录 Git 的作用官网介绍简明概要 Git 下载链接Git 的初始配置配置用户初始化本地库 Git 状态查询Git 工作机制本地工作机制远端工作机制 Git 的本地管理操作add 将修改添加至暂存区commit 将暂存区提交至本地仓库日志查询版本穿梭 Git 分支查看分支创建与切换分支跨分支修改与…

变压器绝缘油介质损耗因素测试

试验目的 变压器油又称绝缘油&#xff0c;是一种电介质&#xff0c;是能够耐受电应力的绝缘体。当对介质油施加交流电压时&#xff0c;所通过的电流与其两端的电压相位差并不是90度角&#xff0c;而是比90度角要小一个δ角的&#xff0c;此δ角称为油的介质损耗角。变压器油的…

微服务集成spring cloud sentinel

目录 1. sentinel使用场景 2. sentinel组成 3. sentinel dashboard搭建 4. sentinel客户端详细使用 4.1 引入依赖 4.2 application.properties增加dashboard注册地址 4.3 手动增加限流配置类 4.4 rest接口及service类 4.5 通过dashboard动态配置限流规则 1. sentinel使…

Linux 系统下 GDB 调试器的使用

文章目录 简介GDB 的介绍GDB 的使用 GDB 常用命令及示例查看相关操作断点相关操作运行相关操作变量相关操作分隔窗口操作 简介 GDB 的介绍 GDB 是 GNU 调试程序&#xff0c;是用来调试 C 和 C 程序的调试器。它可以让程序开发者在程序运行时观察程序的内部结构和内存的使用情况…

大数据时代,个人信息数据库保护的挑战及其对策

挑战&#xff1a; 数据泄露&#xff1a;大数据时代&#xff0c;个人信息数据库面临被黑客攻击、内部员工滥用权限等风险&#xff0c;导致个人信息泄露的风险增加。 隐私保护&#xff1a;随着大数据的快速发展&#xff0c;个人信息的采集和分析变得更加广泛和深入。但是&#xf…

初级工程师职称评定条件及流程是什么呢?初级作用是什么?

现在全国统一的助理&#xff08;初级&#xff09;工程师是由人社部颁发的初级工程师证也就是大家说的初级职称。人社部备案&#xff0c;正规可靠&#xff0c;国家认可&#xff0c;评审表、红头文件齐全&#xff0c;可以用于应聘、在职、上岗、加薪、评级、评职称或者企业升资质…

indexDB入门到精通

前言 由于开发3D可视化项目经常用到模型&#xff0c;而一个模型通常是几m甚至是几十m的大小对于一般的服务器来讲加载速度真的十分的慢&#xff0c;为了解决这个加载速度的问题&#xff0c;我想到了几个本地存储的。 首先是cookie,cookie肯定是不行的&#xff0c;因为最多以只…

MPP 还是主流架构吗

MPP 架构&#xff1a; MPP 架构的产品&#xff1a; Impala ClickHouse Druid Doris 很多 OLAP 引擎都采用了 MPP 架构 批处理系统 - 使用场景分钟级、小时级以上的任务&#xff0c;目前很多大型互联网公司都大规模运行这样的系统&#xff0c;稳定可靠&#xff0c;低成本。…

9.1 功率放大电路概述

在实用电路中&#xff0c;往往要求放大电路的末级&#xff08;即输出级&#xff09;输出一定的功率&#xff0c;以驱动负载。能够向负载提供足够信号功率的放大电路称为功率放大电路&#xff0c;简称功放。从能量控制和转换的角度看&#xff0c;功率放大电路与其它放大电路在本…

c++ qt--信号与槽(二) (第四部分)

c qt–信号与槽(二) &#xff08;第四部分&#xff09; 一.信号与槽的关系 1.一对一 2.一对多 3.多对一 4.多对多 还可以进行传递 信号->信号->槽 一个信号控制多个槽的例子&#xff08;通过水平滑块控制两个组件&#xff09; 1.应用的组件 注意这里最下面的组件…

MongoDB快速上手

MongoDB快速上手 MongoDB用起来-快速上手&集群和安全系列 课程目标&#xff1a; 理解MongoDB的业务场景、熟悉MongoDB的简介、特点和体系结构、数据类型等能够在windows和linux下安装和启动MongoDB、图形化管理界面Compass的安装使用掌握MongoDB基本常用命令实现数据的C…

mysql 、sql server 临时表、表变量、

sql server 临时表 、表变量 mysql 临时表 创建临时表 create temporary table 表名 select 字段 [&#xff0c;字段2…&#xff0c;字段n] from 表

项目解决问题

红外 没接收到红外信号时&#xff0c; 会有杂波干扰 STC单片机 STC的串口要用一个定时器作为波特率发生器 开定时器2需要 开定时器0 1 要ET0 1 ET11打开 串口有时候和定时器有冲突 串口发送函数放定时器中断函数中&#xff0c;时间太少可能会导致一直卡在定时器中AUXR | 0x…

精彩回顾 | 风丘科技亮相2023中国汽车测试及质量监控博览会

2023年8月9-11日&#xff0c;风丘科技携手德国Softing、德国IPETRONIK亮相中国汽车测试及质量监控博览会&#xff08;2023 Testing Expo&#xff09;&#xff0c;为大家呈现了在汽车测试、车辆诊断领域里专业的研发测试工具及创新解决方案&#xff0c;吸引了众多客户驻足洽谈。…

MySQL基础篇(四)

多表查询 概述&#xff1a;多表查询就是多张表之间的查询。 回顾&#xff1a;SELECT * FROM table_name 多表查询 from 后面就得跟多张表。如&#xff1a;select * from emp,dept 笛卡尔积&#xff1a;笛卡尔积在数学中&#xff0c;表示两个集合&#xff0c;集合 A 和集合 B…

解决`idea`中`database`工具查询起别名乱码问题

文章目录 解决idea中database工具查询起别名乱码问题场景复现如何解决方式一 设置编码方式二&#xff1a;修改字体 原因说明 解决idea中database工具查询起别名乱码问题 场景复现 使用Idea做查询的并且起别名出现了中文乱码 如何解决 方式一 设置编码 settings->输入框输…