在工作队列中,我们有多个消息的消费者,每个消费者都会进行消息消费,在默认情况下,RabbitMQ会进行消息轮询发送给每一个消费者,因此每个消费者处理的消息数量是一致的。下面直接看我们的主要文件代码

一、pom文件

我们只需要引入RabbitMQ的依赖包即可

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>RabbitMQ</artifactId>
    <version>1.0-SNAPSHOT</version>

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

    </dependencies>

</project>

二、消息生产者Producer

消息生产者代码与上一篇简单模式一样,步骤仍然是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