第三节 Direct路由交换机:队列使用路由键绑定交换机

一、基本模型

       P是生产者,是消息的发出者。

       X是direct类型的交换机,它负责接收生产者的消息,并根据路由键分发消息到指定的队列。

       Q1和Q2是队列。Q1队列只会接收:消息路由键为orange的消息,Q2队列只会接收:消息路由键为black和green的消息。

       C1和C2是消费者,它们负责从队列中获取消息并消费。

        

        上一节中的Fanout类型的交换机,它不管路由键。Fanout类型的交换机收到消息后,直接把消息投递到所有绑定它的队列。

        这一节中的Direct类型的交换机,它在接收到消息后,会查看这个消息的路由键routeKey属性。它会将这个消息投递到专门接收指定路由键的队列。 

        Direct类型的交换机,需要处理路由键。该交换机收到消息后会把消息发送到接收指定routing-key的queue中。

二、使用代码

        代码大致意思:

        有三种类型的消息。美女、股票、美食。

        队列一感兴趣的是美女。

        队列二感兴趣的是股票、美食。

        现在向交换机中发消息,交换机要根据指定的路由键RoutingKey(队列感兴趣的是什么)分发不同种类的消息到感兴趣的队列中。

发送端.java

package com.safesoft.directexchaner.mq03;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author jay.zhou
 * @date 2019/4/23
 * @time 14:22
 */
public class Producer {
    private static final Logger LOGGER = LoggerFactory.getLogger(Producer.class);
    private static final String EXCHANGE_NAME = "local::mq03:exchange:e01";
    private static final String QUEUE_NAME_01 = "local::mq03:queue:q01";
    private static final String QUEUE_NAME_02 = "local::mq03:queue:q02";

    /**
     * 路由键:美女
     */
    private static final String ROUTING_KEY_BEAUTY = "routekey_beauty";
    /**
     * 路由键:股票
     */
    private static final String ROUTING_KEY_STOCK = "routekey_stock";
    /**
     * 路由键:美食
     */
    private static final String ROUTING_KEY_FOOD = "routekey_food";


    public static void main(String[] args) {
        try {
            //连接管理器:我们的应用程序与RabbitMQ建立连接的管理器。
            ConnectionFactory factory = new ConnectionFactory();
            //设置RabbitMQ服务器地址
            factory.setHost("127.0.0.1");
            //设置帐号密码,默认为guest/guest,所以下面两行可以省略
            factory.setUsername("guest");
            factory.setPassword("guest");

            //创建一个连接
            Connection connection = factory.newConnection();
            //创建一个信道
            Channel channel = connection.createChannel();

            //声明一个Direct类型的交换机
            channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
            //申明两个个队列
            /**
             * 第一个参数是queue:要创建的队列名
             * 第二个参数是durable:是否持久化。如果为true,可以在RabbitMQ崩溃后恢复消息
             * 第三个参数是exclusive:true表示一个队列只能被一个消费者占有并消费
             * 第四个参数是autoDelete:true表示服务器不在使用这个队列是会自动删除它
             * 第五个参数是arguments:其它参数
             */
            channel.queueDeclare(QUEUE_NAME_01, true, false, false, null);
            channel.queueDeclare(QUEUE_NAME_02, true, false, false, null);
            //开始绑定
            /**
             * 第一个队列对美女感兴趣
             * 第二个队列对股票和美食感兴趣
             *
             * 第一个参数是queue:要被绑定的队列名
             * 第一个参数是exchange:队列绑定到哪个路由器上
             * 第三个参数是routingKey:队列对这种路由键感兴趣,路由器会把这种routingKey的消息发送给队列
             */
            //队列一对交换机说,关于美女的消息给我
            channel.queueBind(QUEUE_NAME_01, EXCHANGE_NAME, ROUTING_KEY_BEAUTY);
            //队列二对交换机说,关于股票和美食的消息给我
            channel.queueBind(QUEUE_NAME_02, EXCHANGE_NAME, ROUTING_KEY_STOCK);
            channel.queueBind(QUEUE_NAME_02, EXCHANGE_NAME, ROUTING_KEY_FOOD);

            //模拟发送消息
            String message01 = "内衣秀明天在XXX开展";
            String message02 = "中国联通股票大跌";
            String message03 = "黄山美食推荐:蝴蝶面";
            //向交换机发送3个消息,分别是关于美女、股票、美食
            channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY_BEAUTY, null, message01.getBytes("UTF-8"));
            channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY_STOCK, null, message02.getBytes("UTF-8"));
            channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY_FOOD, null, message03.getBytes("UTF-8"));
            LOGGER.info("消息发送成功");

            channel.close();
            connection.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

接收端01.java 

package com.safesoft.directexchaner.mq03;

import com.rabbitmq.client.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * @author jay.zhou
 * @date 2019/4/23
 * @time 14:59
 */
public class Consumer01 {
    private static final Logger LOGGER = LoggerFactory.getLogger(Producer.class);
    private static final String EXCHANGE_NAME = "local::mq03:exchange:e01";
    private static final String QUEUE_NAME_01 = "local::mq03:queue:q01";
    private static final String QUEUE_NAME_02 = "local::mq03:queue:q02";

    /**
     * 路由键:美女
     */
    private static final String ROUTING_KEY_BEAUTY = "routekey_beauty";
    /**
     * 路由键:股票
     */
    private static final String ROUTING_KEY_STOCK = "routekey_stock";
    /**
     * 路由键:美食
     */
    private static final String ROUTING_KEY_FOOD = "routekey_food";

    public static void main(String[] args) {
        try {

            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("127.0.0.1");
            Connection connection = factory.newConnection();
            Channel channel = connection.createChannel();

            //声明一个Direct类型的交换机
            channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
            //申明两队列
            channel.queueDeclare(QUEUE_NAME_01, true, false, false, null);
            //开始绑定
            //队列一对交换机说,关于美女的消息给我
            channel.queueBind(QUEUE_NAME_01, EXCHANGE_NAME, ROUTING_KEY_BEAUTY);

            //模拟接收消息
            Consumer consumer = new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body) throws IOException {
                    final String message = new String(body, "UTF-8");
                    LOGGER.info("队列一收到消息:{}", message);
                }
            };

            //队列一确认收到消息
            channel.basicConsume(QUEUE_NAME_01, true, consumer);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

接收端02.java 

package com.safesoft.directexchaner.mq03;

import com.rabbitmq.client.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * @author jay.zhou
 * @date 2019/4/23
 * @time 14:59
 */
public class Consumer02 {
    private static final Logger LOGGER = LoggerFactory.getLogger(Producer.class);
    private static final String EXCHANGE_NAME = "local::mq03:exchange:e01";
    private static final String QUEUE_NAME_01 = "local::mq03:queue:q01";
    private static final String QUEUE_NAME_02 = "local::mq03:queue:q02";

    /**
     * 路由键:美女
     */
    private static final String ROUTING_KEY_BEAUTY = "routekey_beauty";
    /**
     * 路由键:股票
     */
    private static final String ROUTING_KEY_STOCK = "routekey_stock";
    /**
     * 路由键:美食
     */
    private static final String ROUTING_KEY_FOOD = "routekey_food";

    public static void main(String[] args) {
        try {

            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("127.0.0.1");
            Connection connection = factory.newConnection();
            Channel channel = connection.createChannel();

            //声明一个Direct类型的交换机
            channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
            //申明队列
            channel.queueDeclare(QUEUE_NAME_02, true, false, false, null);
            //开始绑定
            //队列二对交换机说,关于股票和美食的消息给我
            channel.queueBind(QUEUE_NAME_02, EXCHANGE_NAME, ROUTING_KEY_STOCK);
            channel.queueBind(QUEUE_NAME_02, EXCHANGE_NAME, ROUTING_KEY_FOOD);

            //模拟接收消息
            Consumer consumer = new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body) throws IOException {
                    final String message = new String(body, "UTF-8");
                    LOGGER.info("队列二收到消息:{}", message);
                }
            };

            //队列二确认收到消息
            channel.basicConsume(QUEUE_NAME_02, true, consumer);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

        先运行发送端Producer

        登录http://localhost:15672后,可以查看这些队列里面的消息。

        可以看到,队列一已经有一条数据没有被消费,队列二有一条数据没有被消费。

        运行接收者一号Consumer01,运行结果为

        运行接收者二号Consumer02,运行结果为 

        再次查看http://localhost:15672,消息已经成功被消费并确认。

三、总结

        direct(默认方式):就是根据路由键的Key进行发送。如果Key一致,路由器就把数据投递到这个队列中。

        fanout:直接把队列绑定到路由器。路由器在收到消息后,直接把消息投递到队列中,不需要路由键。

                     发送到fanout exchange的所有消息会被转发到与exchange绑定的所有queue,不需要处理路由 

四、源代码下载

        源代码地址:https://github.com/hairdryre/Study_RabbitMQ

        下一篇:第四节 Topic路由交换机:消息转发到关心话题的Queue

        阅读更多:从头开始学RabbimtMQ目录贴

posted @ 2022-07-17 12:14  小大宇  阅读(156)  评论(0编辑  收藏  举报