rabbitmq+netcore6 【4】Routing:路由


官网参考链接: https://www.rabbitmq.com/tutorials/tutorial-four-dotnet.html
其他人的翻译版参考: https://www.cnblogs.com/grayguo/p/5377552.html
以下工作是本人在参考官网的教程下,结合自己的理解做的代码流程,更深刻的理解还需要参考官网进行学习哦

1)前言

上一篇文章中我们构建了一个简单的日志系统,我们可以向多个接受者广播消息。

在本文章中,我们将为其添加一个功能使得针对部分消息的接受成为可能。例如:我们将能够将关键错误消息定向到日志文件(即存到磁盘),同时仍然能够在控制台上打印所有日志消息(不对非错误信息进行存储,节约了磁盘空间)

上一篇文章中,我们写了如下的绑定,将logs交换机绑定给所有的队列,这样所有的队列都能接收到转发的消息

channel.QueueBind(queue: queueName,
                  exchange: "logs",
                  routingKey: "");

若想指定某队列接收消息需要设定参数routingKey的值,而不是向上面那样指定为空,为了避免和BasicPublish 方法的参数混淆,我们暂且称之为binding key,下面是我们创建一个带有指定binding key的绑定:

channel.QueueBind(queue: queueName,
                  exchange: "direct_logs", // 交换机的名字也进行了修改
                  routingKey: "black");

2)Direct exchange 直接类型的交换机

我们之前的日志系统,把接受到的消息广播给所有的接受者,我们将要扩展它使得其能够根据消息的级别来过滤发送消息,例如我们想让记录日志的接受者仅仅接受严重性级别的错误消息,而不用在警告和信息级别的消息上浪费磁盘空间。

我们知道交换机类型分为 directtopicheadersfanout 。其中direct类型的交换机会将消息会被发送到其binding key 和消息的routing key 完全匹配的队列上,所以可以使用该类型的交换机实现消息的过滤。
在这里插入图片描述
一个带有routing key为"orange"的消息,会被路由到队列Q1上;带有routing key为"black" 或 "green"的消息将会被路由到队列Q2上。

3)Multiple bindings 多绑定

在这里插入图片描述
使用一个binding key 绑定多个队列完全是合法的,在我们案例中我们可以在 路由X 和 队列Q1,Q2中同时添加一个binding key为"black"的绑定,在这种情况下路由 X 将会像 fanout交换机一样把匹配到的消息发送给所有的接受者即,路由会把binding key 为"black"的消息发送给Q1和Q2。

4)Emitting logs 发送日志

我们把日志级别作为路由的rouing key,这样接收者就可以根据日志级别选择接受其感兴趣的日志。
首先我们需要创建一个交换机

channel.ExchangeDeclare(exchange: "direct_logs", type: "direct");

然后准备发送的消息, 其中severity变量 分为以下几种:“info”,“warning”,“error”.
在这里插入图片描述

var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "direct_logs",
                     routingKey: severity,
                     basicProperties: null,
                     body: body);

之前的写法如下(可以对比来看):
在这里插入图片描述

5)Subscribing 订阅

接受消息和之前的一样,唯一的区别就是我们将会为我们感兴趣的每一个级别的消息新建绑定:

var queueName = channel.QueueDeclare().QueueName;

foreach(var severity in args)
{
    channel.QueueBind(queue: queueName,
                      exchange: "direct_logs",
                      routingKey: severity); // 添加了bindingKey,用来指定队列
}

6)综合以上代码

准备工作

新建一个netcore6的控制台项目,添加RabbitMQ的包依赖

NuGet\Install-Package RabbitMQ.Client -Version 6.4.0

在这里插入图片描述
新建一个类MainClass,注释掉program.cs的代码,使MainClass中的tatic void Main(string[] args)作为程序的入口
按照此方法新建三个netcore6的控制台项目,分别代表生产者,消费者1,消费者2,消费者3

此代码为本人的简化版与官网代码略有不同,先运行两个消费者(一个只接收error信息,另一个只接收info信息),再运行生产者(生产者要先输入信息来源回车,再输入具体信息)

生产者

using RabbitMQ.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ProjectSendDirect
{
    public class MainClass
    {
        static void Main()
        {
            var factory = new ConnectionFactory()
            {
                HostName = "localhost",
                UserName = "lyh",
                Password = "1211",
            };
            using(var connection = factory.CreateConnection())
            {
                using(var channel = connection.CreateModel())
                {
                    channel.ExchangeDeclare(exchange:"direct_logs", type:ExchangeType.Direct);
                    var tmp = Console.ReadLine();
                    var severity = string.IsNullOrEmpty(tmp)?"info":tmp;
                    var message = Console.ReadLine();
                    while(!string.IsNullOrEmpty(severity) && !string.IsNullOrEmpty(message))
                    {
                        var body = Encoding.UTF8.GetBytes(message);
                        channel.BasicPublish(exchange:"direct_logs",routingKey:severity,basicProperties:null,body:body);
                        Console.WriteLine("[x] Sent {0}:{1}", severity, message);
                        tmp = Console.ReadLine();
                        severity = string.IsNullOrEmpty(tmp) ? "info" : tmp;
                        message = Console.ReadLine();
                    }
                    Console.WriteLine("Press [Enter] to exit");
                    Console.ReadLine();
                }
            }

        }
    }
}

消费者1

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ProjectReceiveDirect1
{
    public class MainClass
    {
        static void Main()
        {
            var factory = new ConnectionFactory()
            {
                HostName = "localhost",
                UserName = "lyh",
                Password = "1211"
            };
            using(var connection = factory.CreateConnection())
            {
                using(var channel = connection.CreateModel())
                {
                    channel.ExchangeDeclare(exchange: "direct_logs", type: ExchangeType.Direct);
                    var queueName = channel.QueueDeclare().QueueName;

                    channel.QueueBind(queue: queueName, exchange: "direct_logs", routingKey: "error");
                    Console.WriteLine("[x1] Waiting for message.");
                    var consumer = new EventingBasicConsumer(channel);
                    consumer.Received += (model, ea) =>
                    {
                        var body = ea.Body.ToArray();
                        var message = Encoding.UTF8.GetString(body);
                        var routingKey = ea.RoutingKey;
                        Console.WriteLine("[x1] Received {0}:{1}", routingKey, message);
                    };
                    channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer);
                    Console.WriteLine("Press [enter] to exit");
                    Console.ReadLine();
                }
            }
        }
    }
}

消费者2

基本与消费者一致,只有输出部分有所不同

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ProjectReceiveDirect2
{
    public class MainClass
    {
        static void Main()
        {
            var factory = new ConnectionFactory()
            {
                HostName = "localhost",
                UserName = "lyh",
                Password = "1211"
            };
            using (var connection = factory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    channel.ExchangeDeclare(exchange: "direct_logs", type: ExchangeType.Direct);
                    var queueName = channel.QueueDeclare().QueueName;

                    channel.QueueBind(queue: queueName, exchange: "direct_logs", routingKey: "info");
                    Console.WriteLine("[x2] Waiting for message.");
                    var consumer = new EventingBasicConsumer(channel);
                    consumer.Received += (model, ea) =>
                    {
                        var body = ea.Body.ToArray();
                        var message = Encoding.UTF8.GetString(body);
                        var routingKey = ea.RoutingKey;
                        Console.WriteLine("[x2] Received {0}:{1}", routingKey, message);
                    };
                    channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer);
                    Console.WriteLine("Press [enter] to exit");
                    Console.ReadLine();
                }
            }
        }
    }
}

消费者3

与前两个消费者基本一致,只有输出略有不同

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ProjectReceiveDirect3
{
    public class MainClass
    {
        static void Main()
        {
            var factory = new ConnectionFactory()
            {
                HostName = "localhost",
                UserName = "lyh",
                Password = "1211"
            };
            using (var connection = factory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    channel.ExchangeDeclare(exchange: "direct_logs", type: ExchangeType.Direct);
                    var queueName = channel.QueueDeclare().QueueName;

                    channel.QueueBind(queue: queueName, exchange: "direct_logs", routingKey: "info");
                    Console.WriteLine("[x3] Waiting for message.");
                    var consumer = new EventingBasicConsumer(channel);
                    consumer.Received += (model, ea) =>
                    {
                        var body = ea.Body.ToArray();
                        var message = Encoding.UTF8.GetString(body);
                        var routingKey = ea.RoutingKey;
                        Console.WriteLine("[x3] Received {0}:{1}", routingKey, message);
                    };
                    channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer);
                    Console.WriteLine("Press [enter] to exit");
                    Console.ReadLine();
                }
            }
        }
    }
}

运行结果

验证:一个交换机可以绑定多个队列,绑定相同routingkey(如info)的队列接收到相同的消息
在这里插入图片描述
验证:一个交换机可以绑定多个队列,绑定多个routingkey(如info、error)该队列接收到两个routingkey绑定的消息。
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的Spring Boot RabbitMQ应用程序的完整application.yml配置代码示例: ```yaml spring: rabbitmq: host: localhost port: 5672 username: guest password: guest virtual-host: / listener: simple: acknowledge-mode: manual concurrency: 1 max-concurrency: 1 template: exchange: example.exchange routing-key: example.routingKey ``` 解释: - `spring.rabbitmq.host`:RabbitMQ服务器的主机名或IP地址。 - `spring.rabbitmq.port`:RabbitMQ服务器的端口号。 - `spring.rabbitmq.username`:连接RabbitMQ服务器的用户名。 - `spring.rabbitmq.password`:连接RabbitMQ服务器的密码。 - `spring.rabbitmq.virtual-host`:连接RabbitMQ服务器的虚拟主机。 - `spring.rabbitmq.listener.simple.acknowledge-mode`:确认模式,这里是手动确认模式。 - `spring.rabbitmq.listener.simple.concurrency`:消费者线程数。 - `spring.rabbitmq.listener.simple.max-concurrency`:最大消费者线程数。 - `spring.rabbitmq.template.exchange`:消息发送时使用的交换机名。 - `spring.rabbitmq.template.routing-key`:消息发送时使用的路由键。 你也可以通过application.yml文件配置RabbitMQ的其他参数,例如: ```yaml spring: rabbitmq: host: localhost port: 5672 username: guest password: guest virtual-host: / listener: simple: acknowledge-mode: manual concurrency: 1 max-concurrency: 1 template: exchange: example.exchange routing-key: example.routingKey cache: channel: size: 100 checkout-timeout: 5000 connection: mode: connection size: 10 validated: true ``` 解释: - `spring.rabbitmq.cache.channel.size`:通道缓存的大小。 - `spring.rabbitmq.cache.channel.checkout-timeout`:通道缓存中的通道检出超时时间(毫秒)。 - `spring.rabbitmq.cache.connection.mode`:缓存模式,这里是连接模式。 - `spring.rabbitmq.cache.connection.size`:连接缓存的大小。 - `spring.rabbitmq.cache.connection.validated`:连接是否需要验证。 请注意,以上参数仅为示例,具体配置可能因应用程序需求而异。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值