rabbitmq exchange- 交换机

定义

交换机是用于接受消息,并且根据路由键转发消息到所绑定的消息队列上。

工作原理

工作原理如图:
在这里插入图片描述
蓝色的模块:他是消息生产 者的工作流程,消息生产者负责生产消息,并将消息发送到exchange交换机上,然后exchange通过路由匹配将得到的消息存放到对应的消息队列上。
绿色模块:代表消息的消费者的工作流程,消费者通过监听队列得到队列里存放的消息,然后进行消费。
黄色模块:代表交换机匹配路由键的过程。
红色模块:代表整个rabbitmq的服务。

交换机属性

name : 代表交换机的名称
type: 交换机的类型, 包含:direct, topic,fannout,headers
durability:交换机是否需要持久化, true 代表持久化
auto delete: 是否自动删除,该参数如果为TRUE,那么它上面绑定的最后一个队列被删除时,交换机就会自动删除。
internal: 代表当前交换机是否被rabbitmq内部使用。

交换机的类型

direct exchange

定义
所有发送到 direct exchange 的消息,都会按照route key 的规则精确绑定到所对应的队列上。

注意: direct exchange 可以使用rabbitmq自动的default
exchange,所以不需要对exchange进行任何的绑定操作,消息传递时会按照route key的规则严格匹配.

原理示意图
在这里插入图片描述

实例代码


public class Consumer {
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");

        //根据工厂创建链接
        Connection connection = connectionFactory.newConnection();

        //通过 connection 创建 一个 channel
        Channel channel = connection.createChannel();

        //通过渠道接受数据
        String queueName = "test.direct";
        
        //定义exchange的名称
        String exchangeName = "test_direct_change";
        //定义exchange的类型
        String exchangeType = "direct";
        
        channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null);
        channel.queueDeclare(queueName, true, false, false, null);
         //利用交换机绑定 routekey 和 queue的关系
        channel.queueBind(queueName, exchangeName, routeKey);
        //创建消费者
        QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
        //设置渠道
        channel.basicConsume(queueName, true, queueingConsumer);

        while (true) {
            //获取消息 的deliver
            QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
            String msg = new String(delivery.getBody());
            System.out.println("获取到的消息:" + msg);
        }
    }
}

这是消费者的代码,它定义了交换机的名称和交换机的 类型,以及消息队列的名称等信息。

public class Producer {
    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);

        Connection collection =  connectionFactory.newConnection();

        //创建信道
        Channel channel = collection.createChannel();
        String changeName = "test_direct_change";
        channel.basicPublish(changeName, "test.direct",  null, "send direct exchange message".getBytes());
        channel.close();
        collection.close();
    }
}

这是生产者的代码,由于它的routekey和消费者定义queue的名称一致,所以消费者可以接受到生产者的消息
**运行效果
**
但如果我们将生产者的route key 换成 channel.basicPublish(changeName, "test.direct.name", null, "send direct exchange message".getBytes());
再次运行,结果如图
在这里插入图片描述
消费端未收到任何消息

topic exchange

定义
如果将消息发送到 topic exchange 上,那么它会按照一定的规则模糊匹配到对应的消息队列上。匹配原理和 sql like 相似

注意:可以使用通配符来模糊匹配
* 可以匹配一个单词
# 可以匹配一个或多个单词

匹配原理如图:
在这里插入图片描述

代码演示
用# 匹配

public class TopicConsumer {
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");

        //根据工厂创建链接
        Connection connection = connectionFactory.newConnection();

        //通过 connection 创建 一个 channel
        Channel channel = connection.createChannel();

        //通过渠道接受数据
        String queueName = "test_topic_queue";

        //定义exchange的名称
        String exchangeName = "test_topic_change";
        //定义exchange的类型
        String exchangeType = "topic";

        //定义route key
        String routeKey = "test.#";

        channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null);

        channel.queueDeclare(queueName, true, false, false, null);

        //利用交换机绑定 routekey 和 queue的关系
        channel.queueBind(queueName, exchangeName, routeKey);
        //创建消费者
        QueueingConsumer queueingConsumer = new QueueingConsumer(channel);

        //设置渠道
        channel.basicConsume(queueName, true, queueingConsumer);

        while (true) {
            //获取消息 的deliver
            QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
            String msg = new String(delivery.getBody());
            System.out.println("获取到的消息:" + msg);
        }
    }
}

这是消费者的代码

public class TopicProducer {
    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);

        Connection collection =  connectionFactory.newConnection();

        //创建信道
        Channel channel = collection.createChannel();
        String changeName = "test_topic_change";
        channel.basicPublish(changeName, "test.topic.age",  null, "send topic age exchange message".getBytes());
        channel.basicPublish(changeName, "test.topic.name",  null, "send topic name exchange message".getBytes());
        channel.close();
        collection.close();
    }
}

这是生产者的代码
我们来看看运行结果
在这里插入图片描述

从图上我么可以很清楚的看 出来,我们发生了两个消息由于我们是用的# 匹配的,所以我们能收到所有的消息。
来我们再看看 * 的匹配

public class TopicConsumer {
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");

        //根据工厂创建链接
        Connection connection = connectionFactory.newConnection();

        //通过 connection 创建 一个 channel
        Channel channel = connection.createChannel();

        //通过渠道接受数据
        String queueName = "test_topic_queue";

        //定义exchange的名称
        String exchangeName = "test_topic_change";
        //定义exchange的类型
        String exchangeType = "topic";

        //定义route key
        String routeKey = "test.*";

        channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null);

        channel.queueDeclare(queueName, true, false, false, null);

        //利用交换机绑定 routekey 和 queue的关系
        channel.queueBind(queueName, exchangeName, routeKey);
        //创建消费者
        QueueingConsumer queueingConsumer = new QueueingConsumer(channel);

        //设置渠道
        channel.basicConsume(queueName, true, queueingConsumer);

        while (true) {
            //获取消息 的deliver
            QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
            String msg = new String(delivery.getBody());
            System.out.println("获取到的消息:" + msg);
        }
    }
}

这是消费者的代码

public class TopicProducer {
    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);

        Connection collection =  connectionFactory.newConnection();

        //创建信道
        Channel channel = collection.createChannel();
        String changeName = "test_topic_change";
        channel.basicPublish(changeName, "test.age",  null, "send topic age exchange message".getBytes());
        channel.basicPublish(changeName, "test.topic.name",  null, "send topic name exchange message".getBytes());
        channel.close();
        collection.close();
    }
}

这是生产者的代码
我们发送了两条消息 test.age 和 test.topic.name 来我们运行下代码来看看效果:.
结果如图
在这里插入图片描述
???为什么还是会收到两条消息,难道是我们的代码有问题,还是rabbitmq有问题,别急我们看看控制台
在这里插入图片描述
打开我们的绑定我们会发现,test_topic_queue 绑定了两个不同的规则,原来是因为我们之前已经绑定了test.#的规则,但没有解绑,所以当再我们绑定test.* 时,那么该交换机就会有两个规则,它在接收消息的时候就会同时匹配两个规则,故我们会收到本不该收到的消息。

注意:如果要使用topic来绑定规则时,应事先查看该交换机是否已存在与你当前绑定规则的前缀相同的规则,如果存在应将其先解绑,否则会影响消息接收的准确性。

那么我们先解绑 test.# 规则,再运行程序看看效果:
在这里插入图片描述
如图所示:
当我们解绑之后,我们就只收到 test.age 的消息,未收到 test.topic.name的消息

fonout exchang

定义
它不处理路由键,换句话说,发送到该交换机的消息会转发到与该交换机绑定的队列上。它的性能最好,因为它不会匹配任何的规则

工作原理
工作原理如图
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值