在工作队列中,我们有多个消息的消费者,每个消费者都会进行消息消费,在默认情况下,RabbitMQ会进行消息轮询发送给每一个消费者,因此每个消费者处理的消息数量是一致的。下面直接看我们的主要文件代码
我们只需要引入RabbitMQ的依赖包即可
4.0.0
org.example
RabbitMQ
1.0-SNAPSHOT
com.rabbitmq
amqp-client
5.6.0
消息生产者代码与上一篇简单模式一样,步骤仍然是1创建获取连接,2创建渠道,3声明消息队列,4发送消息,5关闭连接步骤。
package com.xiaohui.rabbitmq.work;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.xiaohui.rabbitmq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 生产者
*/
public class Producer {
public static final String QUEUE_NAME = "work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
//创建渠道
Channel channel = connection.createChannel();
//声明创建队列
channel.queueDeclare(QUEUE_NAME,true,false, false, null);
for (int i = 1; i <= 20; i++) {
//发送消息
String msg = "小兔子来了。。。。"+i;
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
}
//释放资源(关闭渠道 以及连接)
channel.close();
connection.close();
}
}
在工作队列中我们使用了两个消息消费者进行处理消息。注意:此处我们分别使用两种不同的消息接收确认代码实现;
1,autoAck(ture) 一旦消息由服务端送达就作为消息接收确认,然后就会中消息队列中删除(Consumer1中实现);
2,autoAck(false)另一种我们设置为有消费客户端代码手动进行报送消息接收确认,如果没有接到到消息确认,MQ会将该消息重新进行入到消息队列中。然后重新在进行分发(Consumer2中实现)。
Consumer1 代码如下:
package com.xiaohui.rabbitmq.work;
import com.rabbitmq.client.*;
import com.xiaohui.rabbitmq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Cunsumer1 {
public static void main(String[] args) throws IOException, TimeoutException {
//创建消费端链接
Connection connection = ConnectionUtils.getConnection();
//创建消费端渠道
final Channel channel = connection.createChannel();
//声明消费队列
channel.queueDeclare(Producer.QUEUE_NAME, true,false,false,null);
//监听消息
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("==================消费者1开始===================");
System.out.println("路由的key为:"+envelope.getRoutingKey());
System.out.println("交换机为:"+envelope.getExchange());
System.out.println("消息ID为:"+envelope.getDeliveryTag());
System.out.println("收到的消息为:"+new String(body,"UTF-8"));
System.out.println("===================消费者1结束==================");
try {
Thread.sleep(1000);
// channel.basicAck(envelope.getDeliveryTag(), false);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
/**
* 第二个参数表示是否 向mqserver自动回复收到
* 第三个参数表示消息回调
*/
channel.basicConsume(Producer.QUEUE_NAME,true,consumer);
}
}
Consumer2 代码如下:
package com.xiaohui.rabbitmq.work;
import com.rabbitmq.client.*;
import com.xiaohui.rabbitmq.utils.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Cunsumer2 {
public static void main(String[] args) throws IOException, TimeoutException {
//创建消费端链接
Connection connection = ConnectionUtils.getConnection();
//创建消费端渠道
final Channel channel = connection.createChannel();
//声明消费队列
channel.queueDeclare(Producer.QUEUE_NAME, true,false,false,null);
//监听消息
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("==============消费者2开始=======================");
System.out.println("路由的key为:"+envelope.getRoutingKey());
System.out.println("交换机为:"+envelope.getExchange());
System.out.println("消息ID为:"+envelope.getDeliveryTag());
System.out.println("收到的消息为:"+new String(body,"UTF-8"));
try {
Thread.sleep(1000);
System.out.println("================消费者2 任务执行结束=====================");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
/**
* 第二个参数表示是否 向mqserver自动回复收到
* 第三个参数表示消息回调
*/
channel.basicConsume(Producer.QUEUE_NAME,false,consumer);
}
}
我们在启动了 两个消费端代码后,我们启动发送端代码:
场景1:我们正常的让程序执行。测试结果为两个消费端,依次进行处理发送的消息。Consumer1 执行 1,3,5,7,9....奇数的消息。Consumer2 执行2,4,6,8,10 偶数的消息内容。
场景2:我们在运行过程中 停止Consumer1的程序,则表现为 Consumer1 执行了 部分消息(如:只有1,3,5)之后,再无消息执行;而Consumer2仍还是只执行了2,4,6,8,10等偶数的消息。消息 7,9,11..等未被执行的消息则会丢失。
场景3:我们在运行过程中 停止Consumer2(手动反馈消息接收确认)的程序后,从打印可以看出,在Consumer2 中未被确认的消息,重进进入消息队列,全部由Consumer1 完成执行接收。打印结果如下:
Consumer1:
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:45
收到的消息为:小兔子来了。。。。1
===================消费者1结束==================
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:46
收到的消息为:小兔子来了。。。。3
===================消费者1结束==================
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:47
收到的消息为:小兔子来了。。。。5
===================消费者1结束==================
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:48
收到的消息为:小兔子来了。。。。7
===================消费者1结束==================
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:49
收到的消息为:小兔子来了。。。。9
===================消费者1结束==================
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:50
收到的消息为:小兔子来了。。。。11
===================消费者1结束==================
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:51
收到的消息为:小兔子来了。。。。13
===================消费者1结束==================
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:52
收到的消息为:小兔子来了。。。。15
===================消费者1结束==================
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:53
收到的消息为:小兔子来了。。。。17
===================消费者1结束==================
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:54
收到的消息为:小兔子来了。。。。19
===================消费者1结束==================
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:55
收到的消息为:小兔子来了。。。。10
===================消费者1结束==================
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:56
收到的消息为:小兔子来了。。。。12
===================消费者1结束==================
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:57
收到的消息为:小兔子来了。。。。14
===================消费者1结束==================
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:58
收到的消息为:小兔子来了。。。。16
===================消费者1结束==================
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:59
收到的消息为:小兔子来了。。。。18
===================消费者1结束==================
==================消费者1开始===================
路由的key为:work_queue
交换机为:
消息ID为:60
收到的消息为:小兔子来了。。。。20
===================消费者1结束==================
Consumer2 :
==============消费者2开始=======================
路由的key为:work_queue
交换机为:
消息ID为:1
收到的消息为:小兔子来了。。。。2
================消费者2 任务执行结束=====================
==============消费者2开始=======================
路由的key为:work_queue
交换机为:
消息ID为:2
收到的消息为:小兔子来了。。。。4
================消费者2 任务执行结束=====================
==============消费者2开始=======================
路由的key为:work_queue
交换机为:
消息ID为:3
收到的消息为:小兔子来了。。。。6
================消费者2 任务执行结束=====================
==============消费者2开始=======================
路由的key为:work_queue
交换机为:
消息ID为:4
收到的消息为:小兔子来了。。。。8
================消费者2 任务执行结束=====================
==============消费者2开始=======================
路由的key为:work_queue
交换机为:
消息ID为:5
收到的消息为:小兔子来了。。。。10
Process finished with exit code -1