RabbitMQ 工作队列(Work queues)模式示例
总结自:BV15k4y1k7Ep
模式说明
Work queues
与简单模式相比,多了一个或一些消费端,多个消费端共同消费同一个队列中的消息。消费者之间是竞争的关系。
对于任务过重或任务较多情况使用工作队列可以提高任务处理的速度。
代码
Work queues
与简单模式
的代码是几乎一样的,可以完全复制,并多复制一个消费者进行多个消费者同时消费消息的测试。
1)生产者
这里生产者循环发送了多条消息。
package com.zhangmingge.rabbitmq.work;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.zhangmingge.rabbitmq.ConnectionUtil;
public class Producer {
static final String QUEUE_NAME = "work_queue";
public static void main(String[] args) throws Exception {
// 创建连接
Connection connection = ConnectionUtil.getConnection();
// 创建频道
Channel channel = connection.createChannel();
// 声明(创建)队列
/*
* 参数 1:队列名称
* 参数 2:是否定义持久化队列
* 参数 3:是否独占本次连接
* 参数 4:是否在不使用的时候自动删除队列
* 参数 5:队列其它参数
*/
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
for (int i = 1; i <= 30; i++) {
// 发送信息
String message = "你好;小兔子!work 模式--" + i;
/*
* 参数 1:交换机名称,如果没有指定则使用默认 Default Exchange
* 参数 2:路由 key,简单模式可以传递队列名称
* 参数 3:消息其它属性
* 参数 4:消息内容
*/
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
System.out.println("已发送消息:" + message);
}
// 关闭资源
channel.close();
connection.close();
}
}
2)消费者 1
package com.zhangmingge.rabbitmq.work;
import com.rabbitmq.client.*;
import com.zhangmingge.rabbitmq.ConnectionUtil;
import java.io.IOException;
public class Consumer1 {
public static void main(String[] args) throws Exception {
Connection connection = ConnectionUtil.getConnection();
// 创建频道
final Channel channel = connection.createChannel();
// 声明(创建)队列
/*
* 参数 1:队列名称
* 参数 2:是否定义持久化队列
* 参数 3:是否独占本次连接
* 参数 4:是否在不使用的时候自动删除队列
* 参数 5:队列其它参数
*/
channel.queueDeclare(Producer.QUEUE_NAME, true, false, false, null);
// 一次只能接收并处理一个消息
channel.basicQos(1);
// 创建消费者;并设置消息处理
DefaultConsumer consumer = new DefaultConsumer(channel) {
/*
* consumerTag 消息者标签,在 channel.basicConsume 时候可以指定
* envelope 消息包的内容,可从中获取消息 id,消息 routingKey,交换机,消息和重传标志 (收到消息失败后是否需要重新发送)
* properties 属性信息
* body 消息
*/
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
try {
// 路由 key
System.out.println("路由 key 为:" + envelope.getRoutingKey());
// 交换机
System.out.println("交换机为:" + envelope.getExchange());
// 消息 id
System.out.println("消息 id 为:" + envelope.getDeliveryTag());
// 收到的消息
System.out.println("消费者 1-接收到的消息为:" + new String(body, "utf-8"));
Thread.sleep(1000);
// 确认消息
channel.basicAck(envelope.getDeliveryTag(), false);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
// 监听消息
/*
* 参数 1:队列名称
* 参数 2:是否自动确认,设置为 true 为表示消息接收到自动向 mq 回复接收到了,mq 接收到回复会删除消息,设置为 false 则需要手动确认
* 参数 3:消息接收到后回调
*/
channel.basicConsume(Producer.QUEUE_NAME, false, consumer);
}
}
3)消费者 2
消费者 2 和消费者 1 代码除打印日志不同外,没有区别其他。
package com.zhangmingge.rabbitmq.work;
import com.rabbitmq.client.*;
import com.zhangmingge.rabbitmq.ConnectionUtil;
import java.io.IOException;
public class Consumer2 {
public static void main(String[] args) throws Exception {
...
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
try {
...
System.out.println("消费者 2-接收到的消息为:" + new String(body, "utf-8"));
...
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
...
}
}
测试
启动两个消费者,然后再启动生产者发送消息。到 IDEA 的两个消费者对应的控制台查看是否竞争性地接收到消息。
小结
工作模式与简单模式相比,有不止一个消费端,多个消费端共同消费同一个队列中的消息。
一个队列下的多个消费者之间对于同一个消息是竞争的关系。