RabbitMQ workQueues for Java【入门教程 2】

 入门教程1 我们学到了 P——>队列——>C 这种单一的模式。一个生产者对应一个消费者。那么在实际中可能存在一个生产者对应多个消费者,如在车间里面的生产线,一个流水线生产的部件可能供应对应多个工人小费。那么就引入了今天所讨论的知识。

工作队列


工作队列

我们通过Hello World的例子,从生产者发送一条消息到RabbitMQ,然后消费者接收到这条消息并打印出来。这次我们模拟一个工厂流水线的场景,由工厂任务安排者(生产者P)向流水线(RabbitMQ的队列hello)放入半成品,然后由多个工人(消费者C1和C2)从流水线获取半成品进行处理。 

源码

目录结构: 

 ConnectionUtil是连接rabbitMq的工具类,当前是一个生产者  两个消费者甚至多个消费者。

生产者代码如下:

package wxtest.rabbitMq.workQueue;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.MessageProperties;
import wxtest.rabbitMq.ConnectionUtil;

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

/**
 * 生产者
 */
public class produce {
    private final static String QUEUE_NAME = "hello";

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

        // 创建一个通道
        Channel channel = ConnectionUtil.getConnection().createChannel();
        // 指定一个队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        // 发送消息
        String message = null;
//我们来发送五个消息到消息队列中
        for (int i = 0; i < 5; i++) {
            message = "Hello World! " + i;
            channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
            System.out.println(" [x] Sent '" + message + "'");
        }
        // 关闭频道和连接
        channel.close();
        ConnectionUtil.getConnection().close();
    }

}

消费者1:

package wxtest.rabbitMq.workQueue;

import com.rabbitmq.client.*;
import wxtest.rabbitMq.ConnectionUtil;

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

/**
 * 消费者
 */

public class consumer1 {
    //与生产者的队列名相同
    public static String queue_name = "hello";

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(queue_name, false, false, false, null);
        System.out.println("consumer1 [*] Waiting for messages. To exit press CTRL+C");
        channel.basicQos(1);
        Consumer consumer = 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(" consumer1 [x] Received '" + message + "'");

                try {
                    doWork(message);
                } finally {
                    System.out.println("consumer1 [x] Done");
                    // 消息处理完成确认
                    channel.basicAck(envelope.getDeliveryTag(), false);
                }
            }
        };
        channel.basicConsume(queue_name, false, consumer);
    }

    private static void doWork(String message) {
        try {
            Thread.sleep(1000); // 暂停1秒钟
        } catch (InterruptedException _ignored) {
            Thread.currentThread().interrupt();
        }
    }

}

 

消费者2:

package wxtest.rabbitMq.workQueue;

import com.rabbitmq.client.*;
import wxtest.rabbitMq.ConnectionUtil;

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

/**
 * 消费者
 */
public class consumer2 {
    //与生产者的队列名相同
    public static String queue_name = "hello";

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(queue_name, false, false, false, null);
        System.out.println("consumer2 [*] Waiting for messages. To exit press CTRL+C");
        channel.basicQos(1);
        Consumer consumer = 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(" [consumer2] Received '" + message + "'");

                try {
                    doWork(message);
                } finally {
                    System.out.println("consumer2 [x] Done");
                    // 消息处理完成确认
                    channel.basicAck(envelope.getDeliveryTag(), false);
                }
            }
        };
        channel.basicConsume(queue_name, false, consumer);
    }

    private static void doWork(String message) {
        try {
            Thread.sleep(1000); // 暂停1秒钟
        } catch (InterruptedException _ignored) {
            Thread.currentThread().interrupt();
        }
    }

}

输出结果 消费者1为

consumer1 [*] Waiting for messages. To exit press CTRL+C
 consumer1 [x] Received 'Hello World! 1'
consumer1 [x] Done
 consumer1 [x] Received 'Hello World! 3'
consumer1 [x] Done
输出结果 消费者2为

consumer2 [*] Waiting for messages. To exit press CTRL+C
 [consumer2] Received 'Hello World! 0'
consumer2 [x] Done
 [consumer2] Received 'Hello World! 2'
consumer2 [x] Done
 [consumer2] Received 'Hello World! 4'
consumer2 [x] Done
 

忘记确认 
忘记通过basicAck返回确认信息是常见的错误。这个错误非常严重,将导致消费者客户端退出或者关闭后,消息会被退回RabbitMQ服务器,这会使RabbitMQ服务器内存爆满,而且RabbitMQ也不会主动删除这些被退回的消息。 
如果要监控这种错误,可以使用rabbitmqctl messages_unacknowledged命令打印出出相关的信息。


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值