一般在工作中,都是直接使用已经封装好的mq的程序集进行功能开发。所以很多时候都没有去了解rabbitmq到底是如何封装(实现使用的)。所以心血来潮,简单记录下自己对rabbitmq的简单封装

整体的思路是:约定消息体均继承值Command,消息业务类均继承于Handler,并且业务实体均实现Handle方法。消息发布者发送command;消费者接收到消息时通过反射,触发对应的消费业务。

一,定义消息实体相关

 1 /// <summary>
2 /// command消息接口
3 /// </summary>
4 public interface ICommand
5 {
6 }
7 /// <summary>
8 /// 消息基类
9 /// </summary>
10 public class Command : ICommand
11 {
12 public Command() {
13 Id = Guid.NewGuid();
14 Time = DateTime.UtcNow;
15 }
16 /// <summary>
17 /// Id
18 /// </summary>
19 public Guid Id { get; set; }
20 /// <summary>
21 /// 消息时间
22 /// </summary>
23 public DateTime Time { get; set; }
24 }

实际的消息体

 1     /// <summary>
2 /// 类别变更command
3 /// </summary>
4 public class CategoryChangedCommand : Command
5 {
6 /// <summary>
7 /// 类别Id
8 /// </summary>
9 public Guid CategoryId { get; set; }
10 /// <summary>
11 /// Sku id
12 /// </summary>
13 public Guid SkuId { get; set; }
14 }

二、定义消息处理类

 1     /// <summary>
2 /// 消息处理接口
3 /// </summary>
4 /// <typeparam name="T"></typeparam>
5 public interface IHandler<T> where T : Command
6 {
7 /// <summary>
8 /// 处理消息
9 /// </summary>
10 /// <param name="t"></param>
11 void Handle(T t);
12 }
13 /// <summary>
14 /// 消息处理基类
15 /// </summary>
16 /// <typeparam name="T"></typeparam>
17 public abstract class Handler<T> : IHandler<T> where T : Command
18 {
19 public abstract void Handle(T t);
20
21 }

实现处理类

    /// <summary>
/// 类别变更处理类
/// </summary>
public class CategoryChangeHandler : Handler<CategoryChangedCommand>
{
public override void Handle(CategoryChangedCommand t)
{
Console.WriteLine("sku 类别变化,修改对应listing的类别");
}
}

三、通过反射,定义mq消费者(重,以下代码只是实现简单的direct方式的消费,仅作参考辅助理解)

消费者一般随着程序启动建立,所以一般都是在startup.cs中进行初始化启动监听消费。

1、初始化消费类别字典,字典的约定为command与对应的Handler作为一对。(如果是支持fanout,则可以设置成,一个command类别对应多个Handler)

    private void InitHandler()
{
Assembly assembly = Assembly.LoadFrom(Path.Combine(AppContext.BaseDirectory, "SimpleNetCore.RabbitmqCommon.dll"));
var types = assembly.GetTypes().Where(p => p.IsClass && !p.IsAbstract && p.GetInterfaces().Any(x => x.Name == "IHandler`1"));
foreach (var type in types)
{
var handleMethod = type.GetMethod("Handle");
if (handleMethod != null)
{
var parameter = handleMethod.GetParameters()[0];
var parameterType = parameter.ParameterType;
_DicHandlerType.Add(parameterType, type);
}
}
}

2、创建消费者

 1   var factory = new ConnectionFactory()
2 {
3 HostName = mqConfig.Host,
4 VirtualHost = mqConfig.VirtualHost,
5 UserName = mqConfig.UserName,
6 Password = mqConfig.Password
7 };
8 foreach (var item in _DicHandlerType)
9 {
10 var connection = factory.CreateConnection();
11
12
13 var channel = connection.CreateModel();
14 channel.QueueDeclare(item.Key.FullName, true, false, false, null);
15 channel.ExchangeDeclare(item.Key.FullName, ExchangeType.Direct, true, false, null);
16 ///定义事件消费者
17 EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
18 consumer.Received += Consumer_Received; ;
19 //消费
20 channel.BasicConsume(item.Key.FullName, false, consumer);
21 //此处不关闭connection,channel,保持开启持续消费
22
23
24 }

3、消费事件方法,通过反射调用真正的业务类进行业务处理

 1         private void Consumer_Received(object sender, BasicDeliverEventArgs e)
2 {
3 var message = Encoding.UTF8.GetString(e.Body.ToArray());
4 #region 业务处理
5 Console.WriteLine(message);
6 #endregion
7
8 EventingBasicConsumer consumer = sender as EventingBasicConsumer;
9 string exchangeName = e.Exchange;
10 var typeItem = _DicHandlerType.FirstOrDefault(p => p.Key.FullName == exchangeName);
11 if (typeItem.Key != null)
12 {
13 var t = JsonHelper.DeserialType(message, typeItem.Key);
14 var obj = Activator.CreateInstance(typeItem.Value);
15 var method = typeItem.Value.GetMethod("Handle");
16 method.Invoke(obj, new object[] { t });
17 }
18 string routeKey = e.RoutingKey;
19 //设置已经被消费
20 consumer.Model.BasicAck(e.DeliveryTag, false);
21
22 }

四、定义MQ消息生产者(重)

 1     /// <summary>
2 /// 消息发布者接口
3 /// </summary>
4 public interface IBusFactory
5 {
6 /// <summary>
7 /// 发送command--针对的是direct方式
8 /// </summary>
9 /// <typeparam name="T"></typeparam>
10 /// <param name="command"></param>
11 void SendCommand<T>(T command) where T : ICommand;
12 }
13 /// <summary>
14 /// 消息发布者
15 /// </summary>
16 public class BusFactory : IBusFactory
17 {
18 private RabbitmqConfig _config;
19 private ConnectionFactory _factory;
20 public BusFactory(IOptions<RabbitmqConfig> config)
21 {
22 this._config = config.Value;
23 this._factory = new ConnectionFactory()
24 {
25 HostName = _config.Host,
26 VirtualHost = _config.VirtualHost,
27 UserName = _config.UserName,
28 Password = _config.Password,
29 };
30 }
31 public void SendCommand<T>(T command) where T : ICommand
32 {
33 string queueName = command.GetType().FullName;
34 string exchangeName = command.GetType().FullName;
35 string routeKey = command.GetType().FullName;
36 using (var connection = _factory.CreateConnection())
37 {
38 using (var channel = connection.CreateModel())
39 {
40 //定义交换机
41 channel.ExchangeDeclare(exchangeName, ExchangeType.Direct, true, false, null);
42 //定义队列
43 channel.QueueDeclare(queueName, true, false, false, null);
44 //绑定
45 channel.QueueBind(queueName, exchangeName, routeKey, null);
46 string message = JsonHelper.Serial(command);
47 byte[] data = Encoding.UTF8.GetBytes(message);
48 //发送消息
49 channel.BasicPublish(exchangeName, routeKey, null, data);
50 }
51 }
52 }
53 }

附 mq配置类

 1     /// <summary>
2 /// rabbitmq 配置类
3 /// </summary>
4 public class RabbitmqConfig
5 {
6 /// <summary>
7 /// 主机地址
8 /// </summary>
9 public string Host { get; set; }
10 /// <summary>
11 /// 用户名称
12 /// </summary>
13 public string UserName { get; set; }
14 /// <summary>
15 /// 密码
16 /// </summary>
17 public string Password { get; set; }
18 /// <summary>
19 /// 虚拟主机名称
20 /// </summary>
21 public string VirtualHost { get; set; }
22 }
 1     /// <summary>
2 /// rabbitmq 配置类
3 /// </summary>
4 public class RabbitmqConfig
5 {
6 /// <summary>
7 /// 主机地址
8 /// </summary>
9 public string Host { get; set; }
10 /// <summary>
11 /// 用户名称
12 /// </summary>
13 public string UserName { get; set; }
14 /// <summary>
15 /// 密码
16 /// </summary>
17 public string Password { get; set; }
18 /// <summary>
19 /// 虚拟主机名称
20 /// </summary>
21 public string VirtualHost { get; set; }
22 }

对应配置文件

1  "RabbitmqConfig": {
2 "Host":"127.0.0.1",
3 "UserName": "qingy",
4 "Password": "r3295",
5 "VirtualHost": "vTest"
6 }

----

以上就是非常简单的封装实现。仅作为参考!

RabbitMQ的简单封装的更多相关文章

  1. .Net Core应用RabbitMQ,及简单封装

    首先,还是万分感谢大家能够抽空来阅读我的文章,万分感谢.今天我带来的是.Net Core中应用RabbitMQ,和简单封装.因为昨天的文章里说了今天要写,所以今天一定要写出来.小编翻阅了很多资料,想要 ...

  2. 关于RabbitMQ的简单理解

    说明:想要理解RabbitMQ,需要先理解MQ是什么?能做什么?然后根据基础知识去理解RabbitMQ是什么.提供了什么功能. 一.MQ的简单理解 1. 什么是MQ? 消息队列(Message Que ...

  3. Android AsyncTask 深度理解、简单封装、任务队列分析、自定义线程池

    前言:由于最近在做SDK的功能,需要设计线程池.看了很多资料不知道从何开始着手,突然发现了AsyncTask有对线程池的封装,so,就拿它开刀,本文将从AsyncTask的基本用法,到简单的封装,再到 ...

  4. FMDB简单封装和使用

    工具:火狐浏览器+SQLite Manager插件 ; Xcode; FMDB库; 效果: 项目地址: https://github.com/sven713/PackFMDB 主要参考这两篇博客: 1 ...

  5. Android--Retrofit+RxJava的简单封装(三)

    1,继续接着上一篇的讲讲,话说如果像上一篇这样的话,那么我们每一次请求一个结构都要创建一堆的Retrofit对象,而且代码都是相同的,我们可以试试封装一下 先创建一个HttpMethods类,将Ret ...

  6. okhttp3 get post 简单封装

    最近打算在新项目中使用 okhttp3, 简单封装了一下异步 get post 因为 CallBack 也是在子线程中执行,所以用到了 Handler public class MyOkHttpCli ...

  7. python网页请求urllib2模块简单封装代码

    这篇文章主要分享一个python网页请求模块urllib2模块的简单封装代码. 原文转自:http://www.jbxue.com/article/16585.html 对python网页请求模块ur ...

  8. 对pymysql的简单封装

    #coding=utf-8 #!/usr/bin/python import pymysql class MYSQL: """ 对pymysql的简单封装 "& ...

  9. iOS开发——UI篇OC篇&UITableView简单封装

    UITableView简单封装 UITableView时iOS开发中使用最多也是最重的一个UI空间,其实在App Store里面的%80以上的应用都用到了这个控件,所以就给大家介绍一下,前面的文章中也 ...

随机推荐

  1. AD技巧之原理图元器件统一重新编号

    本文将简要介绍Altium Designer中如何进行原理图元器件统一命名,这是Altium Designer软件一个小技巧,在学习和工程实践中,都十分有用的技能. 第一步:打开原理图 第二步:点击& ...

  2. 080 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 05 单一职责原则

    080 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 05 单一职责原则 本文知识点:单一职责原则 说明:因为时间紧张,本人写博客过程中只是 ...

  3. 002 01 Android 零基础入门 01 Java基础语法 01 Java初识 02 Java简介

    002 01 Android 零基础入门 01 Java基础语法 01 Java初识 02 Java简介 学习Java的基础语法 Java是一门编程语言,学习的逻辑其实和现实世界的语言是一样的,需要了 ...

  4. python基础-面向对象opp

    上述是实例化对象的一个过程. 类的定义和实例化: class Role(object): #定义一个类, class是定义类的语法,Role是类名,(object)是新式类的写法,必须这样写,以后再讲 ...

  5. matlab中卷积convolution与filter用法

    转自:https://blog.csdn.net/dkcgx/article/details/46652021 转自:https://blog.csdn.net/Reborn_Lee/article/ ...

  6. uni-app引入iconfont字体图标

    1 首先进入你的iconfont项目 很好, 看见圈圈的吗 , 我说蓝色的,记住了,选到这个 ,然后点击下载本地项目, 解压完就是这个了 ,然后把 圈起来的放到你的项目文件里面 ,记得引入的时候路径别 ...

  7. CDH5部署三部曲之一:准备工作

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  8. Avoid mutating a prop directly since the value will be overwritten whenever the parent component re

    子组件修改父组件的值踩坑 Vue1.0升级至2.0之后,直接在子组件修改父组件的值是会报错的 目的是为了阻止子组件影响父组件的数据. 我们都知道在vue中,父组件传入子组件的变量是存放在props属性 ...

  9. Java 合并Word文档

    合并文档可以是将两个包含一定逻辑关系的文档合并成一个完整的文档,也可以是出于方便文档存储.管理的目的合并多个文档为一个文档.下面,就将以上文档操作需求,通过Java程序来实现Word文档合并.合并文档 ...

  10. vs code C语言环境搭建

    最近重温C语言,因为很多练习只是小程序,并不需要Clion和Codeblocks这样工程导向的编译软件,所以下载了vs code,并试图搜索相应的环境,在此过程中发现,网上许多vs code 的c/c ...