RabbitMQ->路由订阅模型(direct)

本文介绍了RabbitMQ的路由订阅模型(direct)。广播模型在分级权限和消息传递场景中不适用,而路由订阅模型可实现消息分级传递。文中设计了实验模型,让不同消费者绑定不同路由键,还给出了代码实现步骤,包括创建常量类、连接工具类、生产者和消费者等,并说明了运行程序的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RabbitMQ->路由订阅模型(direct)

 

思考

广播模型虽然很方便,但是涉及到分别对待处理的时候,就不能处理了。

试想:

班级中,老师通知大家有集体活动,所有学生都接收到此消息。

但是要分配任务,就给部分学 生去分配任务->比如通知班长去统计要参加的人,通知组长传达详细内容 等等

这时广播模式就不是很适用了,因为有分级权限和对应的消息,要传达给不同身份的人。有一些内容是不能让所有人都知道的,而是其中的一部分。

因此路由订阅模型(direct) 就出现了,非常适合这种场景

 

设计实验

我们根据此模型,设计出这个实验模型

其中

消费者1 绑定 Info

消费者2 绑定 Info、Waning

消费者3 绑定 Info、Warning、Error

 

这样,消息生产者发送

路由键值绑定到 Info 的消息的时候,三个消费者都能收到消息。

路由键值绑定到 Warning 的消息的时候,消费者2、消费者3 能就收到消息

路由键值绑定到 Error 的消息的时候,只有消费者3能接收到消息

实现了消息分级传递的场景

 

下面我们使用代码实现

代码实现

首先创建这个实验要用到很多地方的一些数据:交换机的名称、交换机的类型、路由键值、消息等内容,将其存储在一个专门存储常量的类里面

Step1 创建存储常量的类 Constant

public class Constant {

    /** 交换机的名字 */
    public static final String EXCHANGE_NAME = "log_direct";

    /** 交换机的类型 */
    public static final String EXCHANGE_TYPE = "direct";

    /** 路由键值 */
    /** routingKey:info */
    public static final String ROUTING_KEY_INFO = "info";
    /** routingKey:warning */
    public static final String ROUTING_KEY_WARNING = "warning";
    /** routingKey:warning */
    public static final String ROUTING_KEY_ERROR = "error";

    /** 消息内容 */
    /** INFO  */
    public static final String MESSAGE_INFO = ">[消息] 这条消息通过 路由键值["+ ROUTING_KEY_INFO +"] 获取到的消息";
    /** WARNING */
    public static final String MESSAGE_WARNING = ">[消息] 这条消息通过 路由键值["+ ROUTING_KEY_WARNING +"] 获取到的消息";
    /** ERROR */
    public static final String MESSAGE_ERROR = ">[消息] 这条消息通过 路由键值["+ ROUTING_KEY_ERROR +"] 获取到的消息";
}

Step2 创建连接的工具类 ConnectionUtil

工具类功能为 创建连接,销毁资源

public class ConnectionUtil {

    /** Ip 地址 */
    private static final String IP_ADDRESS = "127.0.0.1";
    /** 固定端口 */
    private static final int PORT = 5672;

    // TODO 改成你自己的用户名
    /**  用户名 */
    private static final String USER_NAME = "root";

    // TODO 改成你自己的密码
    /** 密码 */
    private static final String PASSWORD = "dcpnet";

    /**
     * 获取连接
     * @return 连接
     * @throws IOException IOException
     * @throws TimeoutException TimeOutException
     */
    public static Connection getConnection() throws IOException, TimeoutException {
        /** 创建连接工厂 */
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 设置连接工厂属性
        // IP 地址
        connectionFactory.setHost(IP_ADDRESS);
        // 端口
        connectionFactory.setPort(PORT);
        // 用户名
        connectionFactory.setUsername(USER_NAME);
        // 密码
        connectionFactory.setPassword(PASSWORD);
        // 创建新的连接并且返回
        return connectionFactory.newConnection();
    }

    /**
     * 关闭资源
     * @param connection 连接
     * @param channel 信道
     */
    public static void close(Connection connection, Channel channel){
        try {
            channel.close();
            connection.close();
        } catch (IOException | TimeoutException e) {
            e.printStackTrace();
        }
    }
}

Step3 创建生产者 ProducerClient

功能:发送不同的消息,分别到 Info、Warning、Error 路由键值绑定的队列

public class ProducerClient {

    public static void main(String[] args) throws Exception{
        // 获得一个连接
        Connection connection = ConnectionUtil.getConnection();
        // 创建一个信道
        Channel channel = connection.createChannel();

        // 声明交换机 Param1:交换机的名称   Param2:交换机的类型
        // TODO 没有创建交换机的话,将下面这句话取消注释
        //channel.exchangeDeclare(Constant.EXCHANGE_NAME,Constant.EXCHANGE_TYPE);

        // 发布消息
        // INFO 消息
        channel.basicPublish(Constant.EXCHANGE_NAME,Constant.ROUTING_KEY_INFO,null,Constant.MESSAGE_INFO.getBytes());
        // WARNING 消息
        channel.basicPublish(Constant.EXCHANGE_NAME,Constant.ROUTING_KEY_WARNING,null,Constant.MESSAGE_WARNING.getBytes());
        // ERROR 消息
        channel.basicPublish(Constant.EXCHANGE_NAME,Constant.ROUTING_KEY_ERROR,null,Constant.MESSAGE_ERROR.getBytes());

        // 关闭资源
        ConnectionUtil.close(connection,channel);
    }
}

Step4 创建消费者1、2、3 ConsumerClient1、2、3

ConsumerClient1

这个消费者只绑定了 info 的路由键值到交换机

public class ConsumerClient1 {

    public static void main(String[] args) throws Exception{
        // 获取连接
        Connection connection = ConnectionUtil.getConnection();
        // 创建一个信道
        Channel channel = connection.createChannel();

        // 创建一个临时队列,返回队列的名字
        String queueName = channel.queueDeclare().getQueue();

        // 绑定 info 键值
        channel.queueBind(queueName,Constant.EXCHANGE_NAME,Constant.ROUTING_KEY_INFO);

        // 消费消息
        channel.basicConsume(queueName,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("<[消费者1] 接收到消息" + new String(body));
            }
        });
    }
}

ConsumerClient2

这个消费者绑定了 Info、Warning 的路由键值到交换机

public class ConsumerClient2 {

    public static void main(String[] args) throws Exception{
        // 获取连接
        Connection connection = ConnectionUtil.getConnection();
        // 创建一个信道
        Channel channel = connection.createChannel();

        // 创建一个临时队列,返回队列的名字
        String queueName = channel.queueDeclare().getQueue();

        // 绑定 info 键值
        channel.queueBind(queueName,Constant.EXCHANGE_NAME,Constant.ROUTING_KEY_INFO);
        //绑定 waning 键值
        channel.queueBind(queueName,Constant.EXCHANGE_NAME,Constant.ROUTING_KEY_WARNING);

        // 消费消息
        channel.basicConsume(queueName,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("<[消费者2] 接收到消息" + new String(body));
            }
        });
    }
}

ConsumerClient3

这个消费者绑定了 Info、Warning、Error 的路由键值到交换机

public class ConsumerClient3 {

    public static void main(String[] args) throws Exception{
        // 获取连接
        Connection connection = ConnectionUtil.getConnection();
        // 创建一个信道
        Channel channel = connection.createChannel();

        // 创建一个临时队列,返回队列的名字
        String queueName = channel.queueDeclare().getQueue();

        // 绑定 info 键值
        channel.queueBind(queueName,Constant.EXCHANGE_NAME,Constant.ROUTING_KEY_INFO);
        // 绑定 warning 键值
        channel.queueBind(queueName,Constant.EXCHANGE_NAME,Constant.ROUTING_KEY_WARNING);
        // 绑定 error 键值
        channel.queueBind(queueName,Constant.EXCHANGE_NAME,Constant.ROUTING_KEY_ERROR);

        // 消费消息
        channel.basicConsume(queueName,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("<[消费者3] 接收到消息" + new String(body));
            }
        });
    }
}

 

激动人心的时候终于到了!!!

Step5 运行程序

首先确保RabbitMQ 中有 log_direct 交换机,如果没有请创建:

方式一:将生产者中 注释了 TODO 的下面的那行代码取消注释运行生产者

方式二:在web端创建

 

首先运行三个消费者 ConcumerClient1、2、3

运行生产者 ProducerClient

生产者程序运行成功后,可以看到三个消费者的控制台输出了

消费者1 ->

消费者2 ->

消费者3 ->

可以看到,绑定了响应路由键到交换机的消费者,都受到了对应的消息。

 

加油!让你的努力配得上你想要的生活!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值