RabbitMQ的五种模式

RabbitMQ的五种模式

首先是RabbitMQ的准备工作:
pom.xml

​ 必须导入RabbitMQ依赖包

		<!--RabbitMQ-client-->
		<dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>3.6.2</version>
		</depe·ndency>

ConnectionUtil.java

package org.alva.Utils;

import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * <一句话描述>,RabbitMQ的连接工具类
 * <详细介绍>,
 *
 */
public class ConnectionUtil {
    public static Connection getConnection(String host, int port, String vhost, String username, String password) throws IOException, TimeoutException {
        //1.定义连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        //2.设置服务器地址
        connectionFactory.setHost(host);
        //3.设置端口
        connectionFactory.setPort(port);
        //4.设置虚拟主机,用户名,密码
        connectionFactory.setVirtualHost(vhost);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);

        //5.通过连接工厂获取连接
        Connection connection = connectionFactory.newConnection();
        return connection;
    }
}

接下来开始对五种模式进行讲解:

1.简单队列(模式).

在这里插入图片描述
说明:
P:生产者
C:消费者

模式:
当生产者生产消息后,将消息发往队列.
当队列中有消息时,消费者会实时的监听队列中的消息.如果有消息则会执行消息
一个生产者对应一个消费者

Consumer.java

package org.alva.RabbitMQ;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;
import org.alva.Utils.ConnectionUtil;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * <一句话描述>,消费者
 * <详细介绍>,
 *
 */
public class Consumer {
    private final static String QUEUE_NAME = "hello";

    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //1.获取连接
        Connection connection = ConnectionUtil.getConnection("localhost", 5672, "/", "guest", "guest");
        //2.声明通道
        Channel channel = connection.createChannel();
        //3.声明队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        //4.定义队列的消费者
        QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
        //5.监听队列
        /*
            true:表示自动确认,只要消息从队列中获取,无论消费者获取到消息后是否成功消费,都会认为消息成功消费.
            false:表示手动确认,消费者获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,
            如果消费者一直没有反馈,那么该消息将一直处于不可用状态,并且服务器会认为该消费者已经挂掉,不会再给其发送消息,
            直到该消费者反馈.
        */
        channel.basicConsume(QUEUE_NAME,true,queueingConsumer);
        //6.获取消息
        while (true){
            QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("[x] Received '" + message + "'");
        }
    }
}

Productor.java

package org.alva.RabbitMQ;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import org.alva.Utils.ConnectionUtil;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * <一句话描述>,生产者
 * <详细介绍>,
 *
 */
public class Producer {
    private final static String QUEUE_NAME = "hello";

    public static void main(String[] args) throws IOException, TimeoutException {
        //1.获取连接
        Connection connection = ConnectionUtil.getConnection("localhost", 5672, "/", "guest", "guest");
        //2.声明通道
        Channel channel = connection.createChannel();
        //3.声明(创建)队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //4.定义消息内容
        String message = "hello rabbitmq";
        //5.发布消息
        channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
        System.out.println("[x] send'"+message+"'");
        //6.关闭通道和连接
        channel.close();
        connection.close();

    }
}

2.work模式

在这里插入图片描述
说明:
P:生产者
C:消费者

模式:
当生产者生产消息时,将消息写入队列中,多个消费者争抢执行,并且实现轮询执行方式.
一个生产者对应多个消费者,但是只能有一个消费者获得消息

业务场景:
抢红包的机制/秒杀业务

竞争消费者模式.

生产者

    package org.alva.RabbitMQ.WorkModel;

    import com.rabbitmq.client.Channel;
    import com.rabbitmq.client.Connection;
    import org.alva.Utils.ConnectionUtil;

    import java.io.IOException;
    import java.util.concurrent.TimeoutException;

    /**
     * <一句话描述>,生产者
     * <详细介绍>,Work模式下的生产者
     *
     */
    public class Producter {
        public static final String QUEUE_NAME = "work_queue";

        public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
            //1.获取连接
            Connection connection = ConnectionUtil.getConnection("localhost", 5672, "/", "guest", "guest");
            //2.声明信道
            Channel channel = connection.createChannel();
            //3.声明(创建)队列
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
            //4.定义消息内容,发布多条消息
            for (int i = 0; i < 10; i++) {
                String message = "hello rabbitmq " + i;
                //5.发布消息
                channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
                System.out.println("[x] send message is '" + message + "'");
                //6.模拟发送消息延时,便于展示多个消费者竞争接受消息
                Thread.sleep(i * 10);
            }
            //7.关闭信道
            channel.close();
            //8.关闭连接
            connection.close();
        }
    }

消费者

需要创建两个消费者.

消费者1:每接收一条消息后休眠10毫秒.

    package org.alva.RabbitMQ.WorkModel;

    import com.rabbitmq.client.Channel;
    import com.rabbitmq.client.Connection;
    import com.rabbitmq.client.QueueingConsumer;
    import org.alva.Utils.ConnectionUtil;

    import java.io.IOException;
    import java.util.concurrent.TimeoutException;

    /**
     * <一句话描述>,消费者
     * <详细介绍>,Work模式下的消费者
     *
     */
    public class Consumer1 {
        public static final String QUEUE_NAME = "work_queue";

        public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
            //1.获取连接
            Connection connection = ConnectionUtil.getConnection("localhost", 5672, "/", "guest", "guest");
            //2.声明通道
            Channel channel = connection.createChannel();
            //3.声明队列
            channel.queueDeclare(QUEUE_NAME,false,false,false,null);
            //同一时刻服务器只会发送一条消息给消费者
    //        channel.basicQos(1);

            //4.定义队列的消费者
            QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
            //5.监听队列,手动返回完成状态
            channel.basicConsume(QUEUE_NAME,false,queueingConsumer);
            //6.获取消息
            while (true){
                QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
                String message = new String(delivery.getBody());
                System.out.println("[x] received message : '"+message+"'");
                //休眠10毫秒
                Thread.sleep(10);
                //返回确认状态
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
            }
        }
    }

消费者2:每接收一条消息后休眠1000毫秒

    package org.alva.RabbitMQ.WorkModel;

    import com.rabbitmq.client.Channel;
    import com.rabbitmq.client.Connection;
    import com.rabbitmq.client.QueueingConsumer;
    import org.alva.Utils.ConnectionUtil;

    import java.io.IOException;
    import java.util.concurrent.TimeoutException;

    /**
     * <一句话描述>,
     * <详细介绍>,
     *
     */
    public class Consumer2 {
        public static final String QUEUE_NAME = "work_queue";

        public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
            Connection connection = ConnectionUtil.getConnection("localhost", 5672, "/", "guest", "guest");
            Channel channel = connection.createChannel();
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
    //        channel.basicQos(1);
            QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
            channel.basicConsume(QUEUE_NAME,false,queueingConsumer);
            while (true){
                QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
                String message = new String(delivery.getBody());
                System.out.println("[x] received message : '" + message + "'");
                Thread.sleep(1000);
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
            }
        }
    }

测试结果
首先生产者一次打印从0-9条消息
然后是消费者1:结果为打印偶数条消息(注:先启动的消费者为消费者1)
消费者2:结果为打印奇数条消息

结论:

  • 消费者1和消费者2获取到的消息内容是不同的,也就是说同一个消息只能被一个消费者获取.
  • 消费者1和消费者2分别获取奇数条消息和偶数条消息,两种获取消息的条数是一样的.
    前面我们说这种模式是竞争消费者模式,一条队列被多个消费者监听,这里两个消费者,其中消费者1和消费者2在获取消息后分别休眠了10毫秒和1000毫秒,也就是说两个消费者获取消息的效率是不一样的,但是结果却是两者获得的消息条数是一样的,这根本不构成竞争关系,那么我们应该怎么办才能让工作效率更高的消费者获取消息更多,也就是消费者1获取消息更多呢?
    能者多劳
        channel.basicQos(1);

增加如上代码,表示同一时刻服务器只会发送一条消息给消费者.消费者1和消费者2获取消息结果如下:

应用场景
效率高的消费者消费消息多,可以用来进行负载均衡.

3.发布/订阅模式

在这里插入图片描述
说明:
P:生产者
C:消费者
X:交换机

模式:
当采用了发布订阅模式时,当生产者发布了消息,经过交换机发往不同的队列.
这时不同的队列中有相同的消息.一个消息被执行多次
一个消费者将消息首先发送到交换器,交换器绑定多个队列,然后被监听该队列的消费者所接收并消费.

使用场景:
群发 微信公众号订阅

*在RabbitMQ中,交换器主要有四种类型:direct,fanout,topic,headers,这里的交换器是fanout.

生产者

    package org.alva.RabbitMQ.PublishModel;

    import com.rabbitmq.client.Channel;
    import com.rabbitmq.client.Connection;
    import org.alva.Utils.ConnectionUtil;

    import java.io.IOException;
    import java.util.concurrent.TimeoutException;

    /**
     * <一句话描述>,发布/订阅模式下的生产者
     * <详细介绍>,
     *
     */
    public class Producer {
        private final static String EXCHANGE_NAME = "fanout_exchange";

        public static void main(String[] args) throws IOException, TimeoutException {
            //1.获取连接
            Connection connection = ConnectionUtil.getConnection("localhost", 5674, "/", "guest", "guest");
            //2.声明信道
            Channel channel = connection.createChannel();
            //3.声明交换器
            channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
            //4.定义消息内容
            String message = "hello rabbitmq";
            //5.发布消息
            channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
            System.out.println("[x] send'" + message + "'");
            //6.关闭通道和连接
            channel.close();
            connection.close();

        }
    }

消费者

消费者1:

    package org.alva.RabbitMQ.PublishModel;

    import com.rabbitmq.client.Channel;
    import com.rabbitmq.client.Connection;
    import com.rabbitmq.client.QueueingConsumer;
    import org.alva.Utils.ConnectionUtil;

    import java.io.IOException;
    import java.util.concurrent.TimeoutException;

    /**
     * <一句话描述>,消费者
     * <详细介绍>,发布/订阅模式下的消费者
     *
     */
    public class Consumer1 {
        public static final String QUEUE_NAME = "fanout_queue_1";

        public static final String EXCHANGE_NAME = "fanout_exchange";

        public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
            //1.获取连接
            Connection connection = ConnectionUtil.getConnection("localhost", 5672, "/", "guest", "guest");
            //2.声明信道
            Channel channel = connection.createChannel();
            //3.声明交换器
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
            //4.绑定队列到交换器
            channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
            //同一时刻服务器只会发送一条消息给消费者
            channel.basicQos(1);

            //5.定义队列的消费者
            QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
            //5.监听队列,手动返回完成状态
            channel.basicConsume(QUEUE_NAME, false, queueingConsumer);
            //6.获取消息
            while (true) {
                QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
                String message = new String(delivery.getBody());
                System.out.println("[消费者1] received message : '" + message + "'");
                //休眠10毫秒
                Thread.sleep(10);
                //返回确认状态
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
            }
        }
    }

消费者2:

    package org.alva.RabbitMQ.PublishModel;

    import com.rabbitmq.client.Channel;
    import com.rabbitmq.client.Connection;
    import com.rabbitmq.client.QueueingConsumer;
    import org.alva.Utils.ConnectionUtil;

    import java.io.IOException;
    import java.util.concurrent.TimeoutException;

    /**
     * <一句话描述>,
     * <详细介绍>,
     *
     */
    public class Consumer2 {
        public static final String QUEUE_NAME = "fanout_queue_2";

        private final static String EXCHANGE_NAME = "fanout_exchange";

        public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
            Connection connection = ConnectionUtil.getConnection("localhost", 5672, "/", "guest", "guest");
            Channel channel = connection.createChannel();
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
            channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"");
            channel.basicQos(1);
            QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
            channel.basicConsume(QUEUE_NAME, false, queueingConsumer);
            while (true) {
                QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
                String message = new String(delivery.getBody());
                System.out.println("[消费者2] received message : '" + message + "'");
                Thread.sleep(1000);
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
            }
        }
    }

注意:消费者1和消费者2两者监听的队列名称是不一样的.

测试结果
消费者1和消费者2都消费了该消息.
ps:这是因为消费者1和消费者2都监听了被同一个交换器绑定的队列.如果消息发送到没有队列绑定的交换器时,消息将丢失,因为交换器没有存储消息的能力,消息只能存储在队列中.

应用场景:
比如一个商城系统需要在管理员上传新的商品图片时,前台系统必须更新图片,日志系统必须记录相应的日志,那么就可以将两个队列绑定到图片上传交换器上,一个用于前台系统刚更新图片,另一个用于日志系统记录日志.

4.路由模式

在这里插入图片描述
说明:
P:生产者
C:消费者
X:交换机

模式:
路由模式是发布订阅模式的升级版.根据不同的路由key实现消息的发送.
生产者将消息发送到direct交换器,在绑定队列和交换器的时候有一个路由key,生产者发送的消息会指定一个路由key,那么消息只会发送到相应key相同的队列,接着监听该队列的消费者消费信息.

使用场景:
可以根据功能模块的业务不同,发往不同的队列中.

生产者

    package org.alva.RabbitMQ.DirectExchange;

    import com.rabbitmq.client.Channel;
    import com.rabbitmq.client.Connection;
    import org.alva.Utils.ConnectionUtil;

    import java.io.IOException;
    import java.util.concurrent.TimeoutException;

    /**
     * <一句话描述>,路由模式下的生产者
     * <详细介绍>,
     *
     */
    public class Producer {
        private final static String EXCHANGE_NAME = "direct_exchange";

        public static void main(String[] args) throws IOException, TimeoutException {
            //1.获取连接
            Connection connection = ConnectionUtil.getConnection("localhost", 5674, "/", "guest", "guest");
            //2.声明信道
            Channel channel = connection.createChannel();
            //3.声明交换器,类型为direct
            channel.exchangeDeclare(EXCHANGE_NAME, "direct");
            //4.定义消息内容
            String message = "hello rabbitmq";
            //5.发布消息
            channel.basicPublish(EXCHANGE_NAME, "update", null, message.getBytes());
            System.out.println("[x] send'" + message + "'");
            //6.关闭通道和连接
            channel.close();
            connection.close();

        }
    }

消费者

消费者1:

    package org.alva.RabbitMQ.DirectExchange;

    import com.rabbitmq.client.Channel;
    import com.rabbitmq.client.Connection;
    import com.rabbitmq.client.QueueingConsumer;
    import org.alva.Utils.ConnectionUtil;

    import java.io.IOException;
    import java.util.concurrent.TimeoutException;

    /**
     * <一句话描述>,消费者
     * <详细介绍>,路由模式下的消费者1
     * <p>
     * 这种模式添加了一个路由键,生产者发布消息的时候添加路由键,消费者绑定队列到交换机时添加键值,
     * 这样就可以接收到需要接收的消息。
     *
     */
    public class Consumer1 {
        public static final String QUEUE_NAME = "direct_queue_1";

        public static final String EXCHANGE_NAME = "direct_exchange";

        public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
            //1.获取连接
            Connection connection = ConnectionUtil.getConnection("localhost", 5672, "/", "guest", "guest");
            //2.声明信道
            Channel channel = connection.createChannel();
            //3.声明队列
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
            //4.绑定队列到交换器,指定路由key为update
            channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "update");
            channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "delete");
            channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "add");
            //同一时刻服务器只会发送一条消息给消费者
            channel.basicQos(1);

            //5.定义队列的消费者
            QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
            //5.监听队列,手动返回完成状态
            channel.basicConsume(QUEUE_NAME, false, queueingConsumer);
            //6.获取消息
            while (true) {
                QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
                String message = new String(delivery.getBody());
                System.out.println("[消费者1] received message : '" + message + "'");
                //休眠10毫秒
                Thread.sleep(10);
                //返回确认状态
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
            }
        }
    }

消费者2:

    package org.alva.RabbitMQ.DirectExchange;

    import com.rabbitmq.client.Channel;
    import com.rabbitmq.client.Connection;
    import com.rabbitmq.client.QueueingConsumer;
    import org.alva.Utils.ConnectionUtil;

    import java.io.IOException;
    import java.util.concurrent.TimeoutException;

    /**
     * <一句话描述>,消费者
     * <详细介绍>,路由模式下的消费者2
     *
     */
    public class Consumer2 {
        public static final String QUEUE_NAME = "direct_queue_2";

        public static final String EXCHANGE_NAME = "direct_exchange";

        public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
            //1.获取连接
            Connection connection = ConnectionUtil.getConnection("localhost", 5672, "/", "guest", "guest");
            //2.声明信道
            Channel channel = connection.createChannel();
            //3.声明队列
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
            //4.绑定队列到交换器,指定路由key为select
            channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "select");
            //同一时刻服务器只会发送一条消息给消费者
            channel.basicQos(1);

            //5.定义队列的消费者
            QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
            //5.监听队列,手动返回完成状态
            channel.basicConsume(QUEUE_NAME, false, queueingConsumer);
            //6.获取消息
            while (true) {
                QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
                String message = new String(delivery.getBody());
                System.out.println("[消费者1] received message : '" + message + "'");
                //休眠10毫秒
                Thread.sleep(10);
                //返回确认状态
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
            }
        }
    }

测试结果

生产者发布消息,指定的路由key为update,消费者1绑定队列和交换器时key分别是update/delete/add;消费者2绑定队列和交换器时key时select.
所以可以猜到生产者发送的消息,只有消费者1能够接收并消费,而消费者2是不能接收的.

应用场景
利用消费者能够有选择性的接收消息的特性,比如商场系统的后台管理系统对于商品进行修改、删除、新增操作都需要更新前台系统的界面展示,而查询操作不需要,那么这两个队列分开接收消息就比较好.

5.主题模式

在这里插入图片描述
说明:
P:生产者
C:消费者
X:交换机

模式:
主题模式是路由模式的升级版,只要满足条件的路由key,都可以接收消息.
上面的路由模式是根据路由key进行完整的匹配(完全相等才发送消息),这里的通配符模式通俗的来讲就是模糊匹配.

通配符的格式:
#号:匹配一个或一组字符(以.分割)
*号:匹配一个词。
例子:
Item.update.aabb item.# 可以匹配
Item.update item.# item. 都可以匹配

生产者

    package org.alva.RabbitMQ.TopicExchange;

    import com.rabbitmq.client.Channel;
    import com.rabbitmq.client.Connection;
    import org.alva.Utils.ConnectionUtil;

    import java.io.IOException;
    import java.util.concurrent.TimeoutException;

    /**
     * <一句话描述>,主题模式下的生产者
     * <详细介绍>,
     *
     */
    public class Producer {
        private final static String EXCHANGE_NAME = "topic_exchange";

        public static void main(String[] args) throws IOException, TimeoutException {
            //1.获取连接
            Connection connection = ConnectionUtil.getConnection("localhost", 5674, "/", "guest", "guest");
            //2.声明信道
            Channel channel = connection.createChannel();
            //3.声明交换器,类型为direct
            channel.exchangeDeclare(EXCHANGE_NAME, "topic");
            //4.定义消息内容
            String message = "hello rabbitmq";
            //5.发布消息
            channel.basicPublish(EXCHANGE_NAME, "update.Name", null, message.getBytes());
            System.out.println("[x] send'" + message + "'");
            //6.关闭通道和连接
            channel.close();
            connection.close();

        }
    }

消费者1

    package org.alva.RabbitMQ.TopicExchange;

    import com.rabbitmq.client.Channel;
    import com.rabbitmq.client.Connection;
    import com.rabbitmq.client.QueueingConsumer;
    import org.alva.Utils.ConnectionUtil;

    import java.io.IOException;
    import java.util.concurrent.TimeoutException;

    /**
     * <一句话描述>,消费者
     * <详细介绍>,主题模式下的消费者1
     *
     */
    public class Consumer1 {
        public static final String QUEUE_NAME = "topic_queue_1";

        public static final String EXCHANGE_NAME = "topic_exchange";

        public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
            //1.获取连接
            Connection connection = ConnectionUtil.getConnection("localhost", 5673, "/", "guest", "guest");
            //2.声明信道
            Channel channel = connection.createChannel();
            //3.声明队列
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
            //4.绑定队列到交换器,指定路由key为update
            channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "update.#");
            //同一时刻服务器只会发送一条消息给消费者
            channel.basicQos(1);

            //5.定义队列的消费者
            QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
            //5.监听队列,手动返回完成状态
            channel.basicConsume(QUEUE_NAME, false, queueingConsumer);
            //6.获取消息
            while (true) {
                QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
                String message = new String(delivery.getBody());
                System.out.println("[消费者1] received message : '" + message + "'");
                //休眠10毫秒
                Thread.sleep(10);
                //返回确认状态
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
            }
        }
    }

消费者2


    package org.alva.RabbitMQ.TopicExchange;

    import com.rabbitmq.client.Channel;
    import com.rabbitmq.client.Connection;
    import com.rabbitmq.client.QueueingConsumer;
    import org.alva.Utils.ConnectionUtil;

    import java.io.IOException;
    import java.util.concurrent.TimeoutException;

    /**
     * <一句话描述>,消费者
     * <详细介绍>,主题模式下的消费者2
     *
     * @author 穆国超
     * @since 设计wiki | 需求wiki
     */
    public class Consumer2 {
        public static final String QUEUE_NAME = "topic_queue_2";

        public static final String EXCHANGE_NAME = "topic_exchange";

        public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
            //1.获取连接
            Connection connection = ConnectionUtil.getConnection("localhost", 5672, "/", "guest", "guest");
            //2.声明信道
            Channel channel = connection.createChannel();
            //3.声明队列
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
            //4.绑定队列到交换器,指定路由key为select
            channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "select.#");
            //同一时刻服务器只会发送一条消息给消费者
            channel.basicQos(1);

            //5.定义队列的消费者
            QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
            //5.监听队列,手动返回完成状态
            channel.basicConsume(QUEUE_NAME, false, queueingConsumer);
            //6.获取消息
            while (true) {
                QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
                String message = new String(delivery.getBody());
                System.out.println("[消费者1] received message : '" + message + "'");
                //休眠10毫秒
                Thread.sleep(1000);
                //返回确认状态
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
            }
        }
    }

分析结果
生产者发送消息绑定的路由key为update.Name;消费者1监听的队列和交换器绑定路由key为update.#;消费者2监听的队列和交换器绑定路由key为select.#.
很显然,消费者1会接收到消息,而消费者2接收不到

6.四种交换器

​ 前面介绍了五种队列模式,但是实际上只有三种,第一种简单队列,第二种工作模式,剩下的三种都是和交换器绑定的合起来称为一种,这节详细介绍交换器.

​ 交换器分为四种,分别是:direct,fanout,topic和headers.

​ 前三种分别对应路由模式,发布订阅模式和通配符模式,headers交换器允许匹配AMQP消息的header而非路由键,除此之外,header交换器和direct交换器完全一致,但是性能却差很多,因此基本上不会用到该交换器,这不做详细介绍.

  • direct
    如果路由键完全匹配的话,消息才会被投放到相应的队列.

  • fanout
    当发送一条消息到fanout交换器上时,它会把消息投放到所有附加在此交换器的上的队列.

  • topic
    设置模糊的绑定方式,"*“操作符将”.“视为分隔符,匹配单个字符;”#“操作符没有分块的概念,它将任意”."均视为关键字的匹配部分,能够匹配多个字符.

7.总结

​ 关于RabbitMQ的五种队列,其实实际使用最多的是最后一种主题模式,通过模糊匹配,使得操作更加自如.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值