RabbitMQ的三种exchange类型

一、Direct类型

1.图解概述
在这里插入图片描述

如图所示,该模式下生产者发送消息给broker中的交换机(一个broker中可以有多个exchange交换机,一个exchange可以绑定多个queue队列),交换机根据这条消息携带的routing-key(123)来分发到这个routing-key对应的队列(queue1),因为queue1这个队列绑定的routing-key也是123,那这时,监听queue1的consumer1这个消费者就拿到了‘“张三”’这条消息,也就是说消费者和routing-key是没有直接关系的,消费者只需要关心应该关注哪个队列。

2.代码实现
2.1 创建一个maven工程,引入如下依赖

  <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>5.7.3</version>
        </dependency>

2.2 编写消息生产者的代码

public class Send {

    public static void main(String[] args) throws IOException, TimeoutException {

        ConnectionFactory connectionFactory = new ConnectionFactory();

        //配置链接信息
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        Connection connection = null; //定义连接
        Channel channel = null; //定义通道

        try {
            connection = connectionFactory.newConnection();
            channel = connection.createChannel();
            //创建一个队列 名为myqueueDirect
            channel.queueDeclare("myqueueDirect", false, false, false, null);
            //再创建一个交换机
            //由于发送消息时必须确保交换机已经创建,这行代码的作用如果该交换机没有则创建,如果存在,则不创建
            channel.exchangeDeclare("directExchange","direct",true);
            //通过routing-key(routing-direct)与队列(myqueueDirect)和交换机(directExchange)进行绑定
            channel.queueBind("myqueueDirect","directExchange","routing-direct");

            String message = "direct模式测试消息";
            //生产者发送消息到directExchange交换机,消息携带的routing-key是routing-direct
            channel.basicPublish("directExchange","routing-direct",null,message.getBytes("utf-8"));

            System.out.println("消息发送完毕");
        }catch (Exception e){

        }finally {
            channel.close();
            connection.close();
        }

    }

}

2.3 编写消费者代码

public class Consumer {

    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //配置链接信息
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        Connection connection = null; //定义连接
        Channel channel = null; //定义通道

        try {
            connection = connectionFactory.newConnection();
            channel = connection.createChannel();
            //创建队列 可以不用创建,这里的作用时如果没有该队列则创建,如果有则放弃创建
            channel.queueDeclare("myqueueDirect", false, false, false, null);
            //再创建一个交换机 可以不用创建,这里的作用时如果没有该交换机则创建,如果有则放弃创建
            channel.exchangeDeclare("directExchange","direct",true);
            //通过routing-key与队列和交换机进行绑定
            channel.queueBind("myqueueDirect","directExchange","routing-direct");

            /**
             * 监听某个队列并获取队列中的数据
             */
            channel.basicConsume("myqueueDirect",true,"",new DefaultConsumer(channel){
                @Override
                public void handleDelivery(java.lang.String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    java.lang.String message = new java.lang.String(body, "utf-8");
                    System.out.println("消费者的消息 " + message);
                }
            });

        }catch (Exception e){

        }finally {

        }
    }

}

运行查看:
在这里插入图片描述

二、Fanout类型

1.图解概述
在这里插入图片描述

刚才的direct模式交换机在绑定queue时是需要一个routing-key的,一个routing-key绑定一个队列,而fanout模式不要routing-key,直接将队列与交换机进行绑定,消费者还是只监听队列就可以。

2.代码实现

2.1 编写生产者代码

public class FanoutSend {
    public static void main(String[] args) throws IOException, TimeoutException {

        ConnectionFactory connectionFactory = new ConnectionFactory();

        //配置链接信息
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        Connection connection = null; //定义连接
        Channel channel = null; //定义通道

        try {
            connection = connectionFactory.newConnection();
            channel = connection.createChannel();

            //fanout模式的发送消息
            //发送消息前定义一下,确保交换机一定存在
            channel.exchangeDeclare("fanoutExchange","fanout",true);

            String message = "fanout模式测试消息";

            //不需要绑定routing-key,第二个参数为空即可
            channel.basicPublish("fanoutExchange","",null,message.getBytes("utf-8"));

            System.out.println("消息发送完毕");
        }catch (Exception e){

        }finally {
            if (channel != null){
                channel.close();
                connection.close();
            }
        }

    }

}

由于fanout模式类似于一种广播模式,所以这次创建2个消费者来监听

2.2 编写消费者1的代码

public class Consumer {

    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //配置链接信息
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        Connection connection = null; //定义连接
        Channel channel = null; //定义通道

        try {
            connection = connectionFactory.newConnection();
            channel = connection.createChannel();
            //由于fanout是一种广播模式,所以这里不需要指定特定的对列名,创建一个随机的队列名
            String queueName = channel.queueDeclare().getQueue();
            //创建一个交换机
            channel.exchangeDeclare("fanoutExchange","fanout",true);
            //fanout模式的交换机不需要绑定routing-key
            channel.queueBind(queueName,"fanoutExchange","");

            //消费者监听队列
            channel.basicConsume(queueName,true,"",new DefaultConsumer(channel){
                @Override
                public void handleDelivery(java.lang.String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    java.lang.String message = new java.lang.String(body, "utf-8");
                    System.out.println("fanout:消费者1接受的消息 " + message);
                }
            });

        }catch (Exception e){

        }finally {

        }
    }

}

2.3 编写消费者2的代码

public class Consumer2 {

    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //配置链接信息
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        Connection connection = null; //定义连接
        Channel channel = null; //定义通道

        try {
            connection = connectionFactory.newConnection();
            channel = connection.createChannel();
            //创建一个随机的队列名
            String queueName = channel.queueDeclare().getQueue();
            //创建一个交换机
            channel.exchangeDeclare("fanoutExchange","fanout",true);
            //fanout模式的交换机不需要绑定routing-key
            channel.queueBind(queueName,"fanoutExchange","");

            /**
             * 监听某个队列并获取队列中的数据
             */
            channel.basicConsume(queueName,true,"",new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    String message = new String(body, "utf-8");
                    System.out.println("fanout:消费者2接受的消息 " + message);
                }
            });

        }catch (Exception e){

        }finally {

        }
    }
    
}

注意:这里一定要先启动两个消费者,否则如果先启动生产者,那么消费者将无法消费到生产者发送的消息。

运行查看:
在这里插入图片描述
在这里插入图片描述
可见fanout模式在发送消息时不需要给消息绑定routing-key,只需要将消息发送到指定交换机即可,交换机会将该消息发送给所有绑定的队列中去。

三、Topic

1.图解概述
在这里插入图片描述
topic类型的交换机使用通配符来动态的将消息发送给相应的队列,
该模式在交换机和队列进行绑定时是需要执行routing-key的,其中 “*” 必须匹配一个单词,“#”匹配0个或多个单词。(1)如果消息携带的routing-key为aa,则该消息会发送到queue1和queue3中去,因为queue2绑定的routing-key为aa. *,也就是aa后面必须要有一个单词。(2)如果消息携带的routing-key为aa.123,则该消息会发送到queue2和queue3中去,因为queue1绑定的routing-key为aa,也就是只能匹配routing-key等于aa的。(3)如果消息携带的routing-key为aa.123.bb,则该消息会发送到queue3中去,因为queue1绑定的routing-key只能匹配routing-key等于aa的。queue2绑定的routing-key只能匹配一个单词,而aa.#可以匹配0个或多个单词。

2.代码实现

2.1 编写生产者代码(第一次测试routing-key为aa)

public class TopicSend {

    public static void main(String[] args) throws IOException, TimeoutException {

        ConnectionFactory connectionFactory = new ConnectionFactory();

        //配置链接信息
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        Connection connection = null; //定义连接
        Channel channel = null; //定义通道

        try {
            connection = connectionFactory.newConnection();
            channel = connection.createChannel();

            //fanout模式的发送消息
            //发送消息前最好定义一下,确保交换机一定存在
            channel.exchangeDeclare("topicExchange","topic",true);

            String message = "topic模式测试消息";

            //需要绑定routing-key,只会向符合routing-key规则的队列中发送消息
            channel.basicPublish("topicExchange","aa",null,message.getBytes("utf-8"));

            System.out.println("消息发送完毕");
        }catch (Exception e){

        }finally {
            if (channel != null){
                channel.close();
                connection.close();
            }
        }

    }

}

2.2 编写routing-key匹配 “aa” 的队列的消费者代码

public class Consumer {

    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //配置链接信息
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        Connection connection = null; //定义连接
        Channel channel = null; //定义通道

        try {
            connection = connectionFactory.newConnection();
            channel = connection.createChannel();
            //创建队列
            channel.queueDeclare("topicQueue",true,false,false,null);
            //再创建一个交换机
            channel.exchangeDeclare("topicExchange","topic",true);
            //绑定routing-key将队列与交换机进行绑定
            channel.queueBind("topicQueue","topicExchange","aa");

            /**
             * 监听某个队列并获取队列中的数据
             */
            channel.basicConsume("topicQueue",true,"",new DefaultConsumer(channel){
                @Override
                public void handleDelivery(java.lang.String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    java.lang.String message = new java.lang.String(body, "utf-8");
                    System.out.println("topic:消费者1(aa)接受的消息 " + message);
                }
            });

        }catch (Exception e){

        }finally {

        }
    }

}

2.3 编写routing-key匹配 “aa.*” 的队列的消费者代码

public class Consumer2 {

    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //配置链接信息
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        Connection connection = null; //定义连接
        Channel channel = null; //定义通道

        try {
            connection = connectionFactory.newConnection();
            channel = connection.createChannel();
            //创建队列
            channel.queueDeclare("topicQueue2",true,false,false,null);
            //再创建一个交换机
            channel.exchangeDeclare("topicExchange","topic",true);
            //绑定routing-key将队列与交换机进行绑定
            channel.queueBind("topicQueue2","topicExchange","aa.*");

            /**
             * 监听某个队列并获取队列中的数据
             */
            channel.basicConsume("topicQueue2",true,"",new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    String message = new String(body, "utf-8");
                    System.out.println("topic:消费者2( aa.* )接受的消息 " + message);
                }
            });

        }catch (Exception e){

        }finally {

        }
    }

}

2.4 编写routing-key匹配 “aa.#” 的队列的消费者代码

public class Consumer3 {

    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //配置链接信息
        connectionFactory.setHost("localhost");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");

        Connection connection = null; //定义连接
        Channel channel = null; //定义通道

        try {
            connection = connectionFactory.newConnection();
            channel = connection.createChannel();
            //创建队列
            channel.queueDeclare("topicQueue3",true,false,false,null);
            //再创建一个交换机
            channel.exchangeDeclare("topicExchange","topic",true);
            //绑定routing-key将队列与交换机进行绑定
            channel.queueBind("topicQueue3","topicExchange","aa.#");

            /**
             * 监听某个队列并获取队列中的数据
             */
            channel.basicConsume("topicQueue3",true,"",new DefaultConsumer(channel){
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    String message = new String(body, "utf-8");
                    System.out.println("topic:消费者3( aa.# )接受的消息 " + message);
                }
            });

        }catch (Exception e){

        }finally {

        }
    }

}

生产者发送消息,运行查看:
在这里插入图片描述
可以看到,只有topicQueue和topicQueue3这两个队列接受到了消息,因为aa匹配这两个队列的routing-key(aa和aa.#)。


将生产的的消息的routing-key改为aa.123
在这里插入图片描述
生产者发送消息,运行查看:
在这里插入图片描述
可以看到,只有topicQueue2和topicQueue3这两个队列接受到了消息,因为aa.123匹配这两个队列的routing-key(aa.*和aa.#)。


将生产的的消息的routing-key改为aa.123.bb
在这里插入图片描述
生产者发送消息,运行查看:
在这里插入图片描述
可以看到,只有topicQueue3这个队列接受到了消息,因为aa.123.bb匹配这队列的routing-key(aa.#)。

猜你喜欢

转载自blog.csdn.net/qq_43750656/article/details/106710697