在整个rabbitmq服务中,生产者发送的所有消息都要先经过交换机(exchange),然后再到队列(queue)中。在往队列写入消息时,如果需要写入不同的策略,只需要修改交换机的转发策略即可(为交换机指定消息写入队列的策略)。
rabbitmq中交换机的类型:
首先看第一种类型DirectExchange
生产者在往交换机发送消息时,会指定一个key,如果key值和交换机与队列之间绑定的key一致,则消息会通过交换机发送到对应的队列中。
应用实例:
通过一个写日志的实例来展示DirectExchange的用法,日志类型分为四种info、debug、warn、error。这四种类型的日志都需要记录到本文中,其中error类型的日志不仅需要记录到文本中,还需要发送邮件给管理员。
实现思路:
生产者
定义一个生产者服务,负责发送日志消息到rabbitmq队列中。生产者服务中需要声明两个队列。
队列一(DirectExchangeLogAllQueue)负责接收所有类型的日志消息(100条消息)。
队列二(DirectExchangeLogErrorQueue)负责接收error类型的日志消息(25条消息)。
消费者
定义二个消费者服务。
消费者服务一负责将四种类型的日志记录到文本中(DirectExchangeConsumerLogAll)(100条消息)。
消费者服务二负责将error类型的日志发送邮件给管理员(DirectExchangeConsumerLogError)(25条消息)。
项目结构:
代码实现:
生产者
using RabbitMQ.Client;
using System;
using System.Collections.Generic;
using System.Text;
namespace AspNetCore.RabbitMQ.MessageProducer.MessageProducer
{
/// <summary>
/// Direct路由
/// </summary>
public class DirectExchange
{
public static void Show()
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";//rabbitmq服务在本地运行
factory.UserName = "guest";//用户名
factory.Password = "guest";//密码
//创建链接
using (IConnection connection = factory.CreateConnection())
{
//创建信道
using (IModel channel = connection.CreateModel())
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("生产者已准备就绪......");
//声明两个队列
channel.QueueDeclare(queue: "DirectExchangeLogAllQueue", durable: true, exclusive: false, autoDelete: false, arguments: null);
channel.QueueDeclare(queue: "DirectExchangeLogErrorQueue", durable: true, exclusive: false, autoDelete: false, arguments: null);
//声明交换机exchange
channel.ExchangeDeclare(exchange: "DirectExchange", type: ExchangeType.Direct, durable: true, autoDelete: false, arguments: null);
//待发送的消息
{
string[] logtypes = { "info", "debug", "warn", "error" };
foreach (string logtype in logtypes)
{
//绑定exchange和queue
channel.QueueBind(queue: "DirectExchangeLogAllQueue", exchange: "DirectExchange", routingKey: logtype);
}
//绑定exchange和queue
channel.QueueBind(queue: "DirectExchangeLogErrorQueue", exchange: "DirectExchange", routingKey: "error");
List<LogMsgModel> logList = new List<LogMsgModel>();
for (int i = 1; i <= 100; i++)
{
if (i % 4 == 0)
{
logList.Add(new LogMsgModel()
{
LogType = "info",
Msg = Encoding.UTF8.GetBytes($"info第{i}条信息")
});
}
if (i % 4 == 1)
{
logList.Add(new LogMsgModel()
{
LogType = "debug",
Msg = Encoding.UTF8.GetBytes($"debug第{i}条信息")
});
}
if (i % 4 == 2)
{
logList.Add(new LogMsgModel()
{
LogType = "warn",
Msg = Encoding.UTF8.GetBytes($"warn第{i}条信息")
});
}
if (i % 4 == 3)
{
logList.Add(new LogMsgModel()
{
LogType = "error",
Msg = Encoding.UTF8.GetBytes($"error第{i}条信息")
});
}
}
Console.WriteLine("生产者发送100条日志消息");
//发送日志消息
foreach (var log in logList)
{
channel.BasicPublish(exchange: "DirectExchange", routingKey: log.LogType, basicProperties: null, body: log.Msg);
Console.WriteLine($"{Encoding.UTF8.GetString(log.Msg)} 已发送");
}
}
}
}
}
}
public class LogMsgModel
{
public string LogType { get; set; }
public byte[] Msg { get; set; }
}
}
main方法:
class Program
{
static void Main(string[] args)
{
//路由类型
DirectExchange.Show();
Console.ReadLine();
}
}
消费者一:
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
namespace AspNetCore.RabbitMQ.MessageConsumer_01.MessageConsumer
{
/// <summary>
/// 消费者 所有日志类型
/// </summary>
public class DirectExchangeConsumerLogAll
{
public static void Show()
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";//rabbitmq服务在本地运行
factory.UserName = "guest";//用户名
factory.Password = "guest";//密码
//创建链接
using (IConnection connection = factory.CreateConnection())
{
//创建信道
using (IModel channel = connection.CreateModel())
{
Console.ForegroundColor = ConsoleColor.Green;
try
{
//基于当前信道创建事件
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body.ToArray());
Console.WriteLine($"{message} 写入文本中...");
};
Console.WriteLine("消费者准备就绪......");
//处理消息
channel.BasicConsume(queue: "DirectExchangeLogAllQueue", autoAck: true, consumer: consumer);
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
}
}
main方法:
class Program
{
static void Main(string[] args)
{
//路由类型
DirectExchangeConsumerLogAll.Show();
Console.ReadLine();
}
}
消费者二:
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
namespace AspNetCore.RabbitMQ.MessageConsumer_02.MessageConsumer
{
/// <summary>
/// 消费者 error日志类型 特殊处理
/// </summary>
public class DirectExchangeConsumerLogError
{
public static void Show()
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";//rabbitmq服务在本地运行
factory.UserName = "guest";//用户名
factory.Password = "guest";//密码
//创建链接
using (IConnection connection = factory.CreateConnection())
{
//创建信道
using (IModel channel = connection.CreateModel())
{
Console.ForegroundColor = ConsoleColor.Green;
try
{
//基于当前信道创建事件
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body.ToArray());
Console.WriteLine($"{message} 已发送邮件通知管理员...");
};
Console.WriteLine("消费者准备就绪......");
//处理消息
channel.BasicConsume(queue: "DirectExchangeLogErrorQueue", autoAck: true, consumer: consumer);
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
}
}
main方法:
class Program
{
static void Main(string[] args)
{
//路由类型
DirectExchangeConsumerLogError.Show();
Console.ReadLine();
}
}
运行结果:
总结:需要分支处理的时候,就可以选择使用Direct类型的交换机。