RabbitMq消息分发机制(三)

  • 消息轮询
  • 公平分发

RabbitMq的5种模式与实例:
参考:https://www.cnblogs.com/Jeely/p/10784149.html

队列和交换机方法使用说明:(关注他学习即可):
参考:https://blog.csdn.net/vbirdbest/article/details/78670550

以下代码gitee中有

首先来个工具类RabbitConnectionUtil:

package com.richfit.richfit;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeoutException;
/**
 * @ClassName RabbitConnectionUtil
 * @Description: RabbitMQ的连接工具类 ,删除已有交换机和队列
 * @Author BruthLi
 * @Date 2020/2/10
 * @Version V1.0
 **/
public class RabbitConnectionUtil {
    public static Connection getConnection(String host, int port, String vhost, String username, String password){
        //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 = null;
        try {
            connection = connectionFactory.newConnection();
        } catch (Exception
                e) {
            e.printStackTrace();
        }
        return connection;
    }
    /**
     * 单独建立一个连接动态删除持久化的Mq队列和交换机随后在关闭
     */
     public static void declearQueueAndExchange(List<String> exchangeNames, List<String> queueNames){
         try {
             Connection connection = RabbitConnectionUtil.getConnection("localhost", 5672, "/", "guest", "guest");
             Channel channel = connection.createChannel();
             //获取已有队列!
             // String queue = channel.queueDeclare().getQueue();
             for (String exchangeName: exchangeNames) {
                 channel.exchangeDelete(exchangeName);
             };
             for (String queueName: queueNames) {
                 channel.queueDelete(queueName);
             }
             channel.close();
             connection.close();
         } catch (IOException e) {
             e.printStackTrace();
         } catch (TimeoutException e) {
             e.printStackTrace();
         }
     }
}

(一)一个生产者多个消费者的消息轮询。

消息轮询:RabbitMQ不会顾虑消息者处理消息的能力,即使其中有的消费者闲置有的消费者高负荷。RabbitMQ会逐个发送消息到在序列中的下一个消费者(而不考虑每个任务的时长等等,且是提前一次性分配,并非一个一个分配)。平均每个消费者获得相同数量的消息,这种方式分发消息机制称为Round-Robin(轮询)。

我这个例子是把两个交换机水平线相连了(amqp-hello 和amqp-hello2)!
在这里插入图片描述(其实一个就够了)先开启多个消费者后开启生产者

代码如下:

生产者:

  //交换机名称
    private static final String EXCHANGE_NAME = "amqp-hello";
    private static final String EXCHANGE_NAME2 = "amqp-hello2";
    //交换机和交换机绑定的key   "mqkey"
    private static final String ExCHANEROUTING_KEY = "mqkey";
    //对列名称
    private static final String QUEUE_NAME = "Hello-Queue1";
    //routingkey 名称
    private static final String ROUTING_KEY = "key-Queue";
      //3:一个生产者多个消费者先开启多个消费者后开启一个生产者,如果开启生产者是代码是先删除之前的队列和交换机在重建则之前开启的多个消费者也就废了。
    //交换机和交换机和队列绑定
       String message;
       //1.获取连接
       Connection connection = RabbitConnectionUtil.getConnection("localhost", 5672, "/", "guest", "guest");
       //2.声明通道
       Channel channel = connection.createChannel();
       //创建交换机 s1:交换机的类型(四种之一)代表交换机用哪种方式与队列连接!
       // 创建一个type=direct 持久化的 非自动删除的交换器
       channel.exchangeDeclare(EXCHANGE_NAME, "direct", true, false, null);
        // 创建一个type=fanout持久化的 非自动删除的交换器
       channel.exchangeDeclare(EXCHANGE_NAME2, "fanout", true, false, null);
       //绑定交换机  destination与队列相连    source与生产者相连
       // exchangeBind(String destination, String source, String routingKey)
         channel.exchangeBind(EXCHANGE_NAME2,EXCHANGE_NAME,ExCHANEROUTING_KEY);
       //3.声明(创建)队列  b:durable是否持久化, 队列的声明默认是存放到内存中的,如果true :rabbitmq重启队列不会丢失但是里面消息没了 false:队列和消息全没了
       //b1:exclusive:是否排外的,有两个作用,一:当连接关闭时connection.close()该队列是否会自动删除
       //b2:autoDelete:是否自动删除,当最后一个消费者断开连接之后队列里面消息是否自动被删除,当consumers = 0时队列里面消息就会自动删除
       channel.queueDeclare(QUEUE_NAME,true,false,false,null);
       //将交换器与队列通过路由键绑定 EXCHANGE_NAME2 为与队列连接的交换机
       channel.queueBind(QUEUE_NAME,EXCHANGE_NAME2,ROUTING_KEY);
       for (int i=0;i<20;i++){
           //4.定义消息内容
           message = "hello rabbitmq";
           //5.发布消息  routingkey 是应用于多个消费者的时候明确如何给多个消费者分配信息
           //BasicProperties props -- 消息的基本属性,例如路由头等。byte[] body -- 消息体
           //void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException;
           //注意此处EXCHANGE_NAME 为与生产者相连的交换机!!   MessageProperties.PERSISTENT_TEXT_PLAIN 代表消息持久化
           channel.basicPublish(EXCHANGE_NAME, ExCHANEROUTING_KEY, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
           System.out.println("[x] send'" + message + "'");
       }
       //6.关闭通道和连接
       channel.close();
       connection.close();
   }

消费者(2个消费者代码是一样的)

public static void main(String[] args)  throws Exception {
        Connection connection = RabbitConnectionUtil.getConnection("127.0.0.1", 5672, "/", "guest", "guest");
        Channel channel = connection.createChannel();
        //3.声明队列
        channel.queueDeclare(QUEUE_NAME,true,false,false,null);
        //4.定义队列的消费者
        //QueueingConsumer queueingConsumer1 = new QueueingConsumer(channel);
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                //用于计数
                anInt+=1;
                String msg = new String(body, "utf-8");
                System.out.println("["+String.valueOf(anInt)+"]:receve msg:" + msg);

               try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } finally {
                    System.out.println("[1] done");
                }
            }
        };
        boolean autoAck = true;
        channel.basicConsume(QUEUE_NAME, autoAck, defaultConsumer);
    }

代码说明:
1:自己之前把队列设成持久化了,想把之前创建的队列和交换器删掉重新创建队列和交换器。于是乎生产者代码中加了相应代码变为如下代码:

public static void main(String[] args) throws Exception{
       List<String> listExchangeName = new ArrayList<>();
       listExchangeName.add(EXCHANGE_NAME);
       listExchangeName.add(EXCHANGE_NAME2);
       List<String> listQueueName = new ArrayList<>();
       listQueueName.add(QUEUE_NAME);
       RabbitConnectionUtil.declearQueueAndExchange(listExchangeName,listQueueName);

       String message;
       //1.获取连接
       Connection connection = RabbitConnectionUtil.getConnection("localhost", 5672, "/", "guest", "guest");
       //2.声明通道
       Channel channel = connection.createChannel();
       //创建交换机 s1:交换机的类型(四种之一)代表交换机用哪种方式与队列连接!
       // 创建一个type=direct 持久化的 非自动删除的交换器
       channel.exchangeDeclare(EXCHANGE_NAME, "direct", true, false, null);
       channel.exchangeDeclare(EXCHANGE_NAME2, "fanout", true, false, null);
       //绑定交换机
       // exchangeBind(String destination, String source, String routingKey)
       channel.exchangeBind(EXCHANGE_NAME2,EXCHANGE_NAME,ExCHANEROUTING_KEY);
       //3.声明(创建)队列  b:durable是否持久化, 队列的声明默认是存放到内存中的,如果true :rabbitmq重启队列不会丢失但是里面消息没了 false:队列和消息全没了
       //b1:exclusive:是否排外的,有两个作用,一:当连接关闭时connection.close()该队列是否会自动删除
       //b2:autoDelete:是否自动删除,当最后一个消费者断开连接之后队列里面消息是否自动被删除,当consumers = 0时队列里面消息就会自动删除
       channel.queueDeclare(QUEUE_NAME,true,false,false,null);
       //将交换器与队列通过路由键绑定 EXCHANGE_NAME2 为与队列连接的交换机
       channel.queueBind(QUEUE_NAME,EXCHANGE_NAME2,ROUTING_KEY);
       for (int i=0;i<20;i++){
           //4.定义消息内容
           message = "hello rabbitmq";
           //5.发布消息  routingkey 是应用于多个消费者的时候明确如何给多个消费者分配信息
           //BasicProperties props -- 消息的基本属性,例如路由头等。byte[] body -- 消息体
           //注意此处EXCHANGE_NAME 为与生产者相连的交换机!!   MessageProperties.PERSISTENT_TEXT_PLAIN 代表消息持久化
           channel.basicPublish(EXCHANGE_NAME, ExCHANEROUTING_KEY, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
           System.out.println("[x] send'" + message + "'");
       }
       //6.关闭通道和连接
       channel.close();
       connection.close();
   }

两个消费者先开启了,最后运行生产者。自己原本想直接在生产者中加 channel.exchangeDelete(exchangeName);和channel.queueDelete(queueName); 删除但是发现删除不了。

原因是:删除队列和交换机必须是删除与当前连接(Connection 和 Chanle)没有任何关系的队列和交换器。要不然必须在一个统一单独封闭的chanle 和 connection中(只用于删除交换机和队列的chanle 和connection)比如RabbitConnectionUtil 的declearQueueAndExchange方法。

2:声明创建队列(除了b没问题,其他待验证) channel.queueDeclare(QUEUE_NAME,false,false,false,null);

 channel.queueDeclare(QUEUE_NAME,b,b1,b2,map)

b: durable 是否持久化, 队列的声明默认是存放到内存中的,如果rabbitmq重启服务(先rabbitmq-service stop后rabbitmq-service start)丢失,如果想重启之后还存在就要使队列持久化,保存到Erlang自带的Mnesia数据库中,当rabbitmq重启之后会读取该数据库。图中简称 D
在这里插入图片描述

b1:exclusive是否排外的:有两个作用,一:当连接关闭时connection.close()该队列是否会自动删除;二:该队列是否是私有的private,如果不是排外的,可以使用两个消费者都访问同一个队列,没有任何问题,如果是排外的,会对当前队列加锁,其他通道channel是不能访问的,如果强制访问会报异常:com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=405, reply-text=RESOURCE_LOCKED - cannot obtain exclusive access to locked queue ‘queue_name’ in vhost ‘/’, class-id=50, method-id=20)一般等于true的话用于一个队列只能有一个消费者来消费的场景。

b2:autoDelete是否自动删除:自动删除的前提:至少有一个消息者连接到这个队列,之后所有与这个队列连接的消息都断开时,才会自动删除,备注:生产者客户端创建这个队列,或者没有消息者客户端连接这个队列时,不会自动删除这个队列。图中简称 AD
在这里插入图片描述

map:队列中的消息什么时候会自动被删除?

    Message TTL(x-message-ttl):设置队列中的所有消息的生存周期(统一为整个队列的所有消息设置生命周期), 也可以在发布消息的时候单独为某个消息指定剩余生存时间,单位毫秒, 类似于redis中的ttl,生存时间到了,消息会被从队里中删除,注意是消息被删除,而不是队列被删除。
        方式一:为该队列的所有消息统一设置相同的声明周期(通过设置过期时间和消费者消费每条信息时间间隔,可以看到生产的信息一部分过期一部分消费掉)

Map<String, Object> arguments = new HashMap<String, Object>();
arguments.put("x-message-ttl", 10000);
// 声明队列时指定队列中的消息过期时间
channel.queueDeclare(QUEUE_NAME, false, false, false, arguments);
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes("UTF-8"));

        方式二:单独为某条消息单独设置时间

channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes("UTF-8"));
for(int i = 1; i <= 5; i++) {
   AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties()
	   .builder().expiration( i * 1000 + "");   
   channel.basicPublish(EXCHANGE_NAME, "", properties.build(), (message + i).getBytes("UTF-8"));
}

    Auto Expire(x-expires): x-expires用于当多长时间没有消费者访问该队列的时候,该队列会自动删除,可以设置一个延迟时间,如仅启动一个生产者,10秒之后该队列会删除,或者启动一个生产者,再启动一个消费者,消费者运行结束后10秒,队列也会被删除

Map<String, Object> arguments = new HashMap<String, Object>();
arguments.put("x-expires", 10000);
channel.queueDeclare(QUEUE_NAME, false, false, false, arguments);
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes("UTF-8"));

    Max Length(x-max-length): 限定队列的消息的最大值长度,超过指定长度将会把最早的几条删除掉, 类似于mongodb中的固定集合,例如保存最新的100条消息, Feature=Lim

    Max Length Bytes(x-max-length-bytes): 限定队列最大占用的空间大小, 一般受限于内存、磁盘的大小, Features=Lim B

    Dead letter exchange(x-dead-letter-exchange): 当队列消息长度大于最大长度、或者过期的等,将从队列中删除的消息推送到指定的交换机中去而不是丢弃掉,Features=DLX

    Dead letter routing key(x-dead-letter-routing-key):将删除的消息推送到指定交换机的指定路由键的队列中去, Feature=DLK

    Maximum priority(x-max-priority):x-max-priority: 设置消息的优先级,优先级值越大,越被提前消费。
使用优先级顺序正好相反 5先被消费 1最后

	    Hello RabbitMQ: 5
		Hello RabbitMQ: 4
		Hello RabbitMQ: 3
		Hello RabbitMQ: 2
		Hello RabbitMQ: 1
Map<String, Object> arguments = new HashMap<String, Object>();
 // 设置队列最大消息数量为5
arguments.put("x-max-priority", 5);
channel.queueDeclare(QUEUE_NAME, false, false, false, arguments);
for(int i = 1; i <= 5; i++) {
	AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties()
		.builder().priority(i);
     channel.basicPublish(EXCHANGE_NAME, "", properties.build(), (message + i).getBytes("UTF-8"));
}

在这里插入图片描述
    Lazy mode(x-queue-mode=lazy): Lazy Queues: 先将消息保存到磁盘上,不放在内存中,当消费者开始消费的时候才加载到内存中

参考:https://blog.csdn.net/vbirdbest/article/details/78670550

3:交换机channel.exchangeDeclare(EXCHANGE_NAME, “direct”, false, false, null);

  Exchange.DeclareOk exchangeDeclare(String exchange,
  String type,
  boolean durable,
  boolean autoDelete,
  boolean internal,
  Map<String, Object> arguments) throws IOException;

    exchange :交换器的名称

    type : 交换器的类型,常见的有direct,fanout,topic等

    durable :设置是否持久化。durable设置为true时表示持久化,反之非持久化.持久化可以将交换器存入磁盘,在服务器重启的时候不会丢失相关信息。

    autoDelete:设置是否自动删除。autoDelete设置为true时,则表示自动删除。自动删除的前提是至少有一个队列或者交换器与这个交换器绑定,之后,所有与这个交换器绑定的队列或者交换器都与此解绑。不能错误的理解—当与此交换器连接的客户端都断开连接时,RabbitMq会自动删除本交换器

    internal:设置是否内置的。如果设置为true,则表示是内置的交换器,客户端程序无法直接发送消息到这个交换器中,只能通过交换器路由到交换器这种方式。

    arguments:其它一些结构化的参数,比如:alternate-exchange

4:交换机删除exchangeDelete

 Exchange.DeleteOk exchangeDelete(String exchange, boolean ifUnused) throws IOException;

ifUnused 用来设置是否在交换器没有被使用的情况下删除。
true:则只有在此交换器没有被使用的情况下才会被删除。当前任务与删除的交换机没有任何关联。
false:无论如何这个交换器都要被删除

5:ack确认
channel.basicConsume(QUEUE_NAME, bollean, queueingConsumer1);

channel执行basicConsume方法时autoAck为false,这就意味着接受者在收到消息后需要主动通知RabbitMQ才能将该消息从队列中删除,否则该在接收者跟MQ连接没断的情况下,消息将会变为untracked状态,一旦接收者断开连接,消息重新变为ready状态。
通知MQ需要调用channel.basicAck(int, boolean),如果不调用,消息永远不会从队列中消失。
该方法第一个参数为一个标志,一般是delivery.getEnvelope().getDeliveryTag(),其实就是一个递增的数字,它表示这个这个队列中第几个消息
在这里插入图片描述
手动处理

//手动确认ack  是否批量处理.true:将一次性ack所有小于deliveryTag的消息
  channel.basicAck(delivery1.getEnvelope().getDeliveryTag(), false);

如果为channel.basicConsume为true则不需要写,自动确认ack。

6:消息持久化设置
    设置消息持久化必须先设置队列持久化,要不然队列不持久化,消息持久化,队列都不存在了,消息存在还有什么意义。消息持久化需要将交换机持久化、队列持久化、消息持久化,才能最终达到持久化的目的。
    方式一:设置deliveryMode=2

channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT, true);
channel.queueDeclare(QUEUE_NAME, true, false, false, arguments);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
String message = "Hello RabbitMQ: ";
// 设置消息持久化
AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties().builder();
properties.deliveryMode(2);  // 设置消息是否持久化,1: 非持久化 2:持久化    
channel.basicPublish(EXCHANGE_NAME, "", properties.build(), message.getBytes("UTF-8"));

方式二:设置BasicProperties为MessageProperties.PERSISTENT_TEXT_PLAIN

channel.queueDeclare(QUEUE_NAME, true, false, false, arguments);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
String message = "Hello RabbitMQ: ";
channel.basicPublish(EXCHANGE_NAME, "", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes("UTF-8"));

(二)一个生产者多个消费者的公平分发

公平分发:则是根据消费者的处理能力来进行分发处理的。这里主要是通过设置prefetchCount 参数来实现的。这样RabbitMQ就会使得每个Consumer在同一个时间点最多处理规定的数量级个数的Message。换句话说,在接收到该Consumer的ack前,它不会将新的Message分发给它。 比如prefetchCount=1,则在同一时间下,每个Consumer在同一个时间点最多处理1个Message,同时在收到Consumer的ack前,它不会将新的Message分发给它。

这个例子是把两个交换机相连了!(其实一个就够了)先开启多个消费者后开启生产者。

1:利用的是channel.basicQos(int prefetch);
channel.basicQos(1) 1就是图中的1
在这里插入图片描述设置每次从队列获取消息的数量 能者多劳的原则不至于做的快的做完了就歇着了,这样是告诉RabbitMQ,再同一时刻,不要发送超过1条消息给一个工作者(worker),直到它已经处理了上一条消息并且作出了响应。这样,RabbitMQ就会把消息分发给下一个空闲的工作者(worker)。公平二字体现在这个能者多劳上。

特别注意:channel.basicQos(1);和channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);是配套使用,不然channel.basicQos(1)不起作用。
使用公平分发,必须关闭自动应答ack,改成手动
原因:

关闭自动应答(Broker发出去就确认不管理消费者处理完了没有)是为了逻辑处理结束前不接受下一条消息,这样哪个消费者逻辑处理的快(处理完后ack返回Broker,随后接收下一条),接收的消息自然就多,从而实现公平分发,按需分发

2:利用了 Thread.sleep(100); 时间不同导致效率不同来做。

代码如下:
生产者(和消息轮询的一样)

 public static void main(String[] args) throws Exception{
       String message;
       //1.获取连接
       Connection connection = RabbitConnectionUtil.getConnection("localhost", 5672, "/", "guest", "guest");
       //2.声明通道
       Channel channel = connection.createChannel();
       //创建交换机 s1:交换机的类型(四种之一)代表交换机用哪种方式与队列连接!
       // 创建一个type=direct 持久化的 非自动删除的交换器
       channel.exchangeDeclare(EXCHANGE_NAME, "direct", false, false, null);
       channel.exchangeDeclare(EXCHANGE_NAME2, "fanout", false, false, null);
       //绑定交换机
       // exchangeBind(String destination, String source, String routingKey)
       channel.exchangeBind(EXCHANGE_NAME2,EXCHANGE_NAME,ExCHANEROUTING_KEY);
       //3.声明(创建)队列  b:durable是否持久化, 队列的声明默认是存放到内存中的,如果true :rabbitmq重启队列不会丢失但是里面消息没了 false:队列和消息全没了
       //b1:exclusive:是否排外的,有两个作用,一:当连接关闭时connection.close()该队列是否会自动删除
       //b2:autoDelete:是否自动删除,当最后一个消费者断开连接之后队列里面消息是否自动被删除,当consumers = 0时队列里面消息就会自动删除
       channel.queueDeclare(QUEUE_NAME,true,false,false,null);
       //将交换器与队列通过路由键绑定 EXCHANGE_NAME2 为与队列连接的交换机
       channel.queueBind(QUEUE_NAME,EXCHANGE_NAME2,ROUTING_KEY);
       for (int i=0;i<20;i++){
           //4.定义消息内容
           message = "hello rabbitmq";
           //5.发布消息  routingkey 是应用于多个消费者的时候明确如何给多个消费者分配信息
           //BasicProperties props -- 消息的基本属性,例如路由头等。byte[] body -- 消息体
           //void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException;
           //注意此处EXCHANGE_NAME 为与生产者相连的交换机!!   MessageProperties.PERSISTENT_TEXT_PLAIN 代表消息持久化
           channel.basicPublish(EXCHANGE_NAME, ExCHANEROUTING_KEY, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
           System.out.println("[x] send'" + message + "'");
       };
       //6.关闭通道和连接
       channel.close();
       connection.close();
   }

消费者(消费者两个是一样的)

  public static void main(String[] args)  throws Exception {
       Connection connection = RabbitConnectionUtil.getConnection("127.0.0.1", 5672, "/", "guest", "guest");
       Channel channel = connection.createChannel();
       //3.声明队列
       channel.queueDeclare(QUEUE_NAME, false, false, false, null);
       //设置每次从队列获取消息的数量 能者多劳的原则不至于做的快的做完了就歇着了!
       channel.basicQos(1);
       //4.定义队列的消费者
       QueueingConsumer queueingConsumer1 = new QueueingConsumer(channel);
        /*
    true:表示自动确认,只要消息从队列中获取,无论消费者获取到消息后是否成功消费,都会认为消息成功消费.
    false:表示手动确认,消费者获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,
    如果消费者一直没有反馈,那么该消息将一直处于不可用状态,并且服务器会认为该消费者已经挂掉,不会再给其发送消息,
    直到该消费者反馈.例如:channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
     */
       //b:ack
       channel.basicConsume(QUEUE_NAME, false, queueingConsumer1);
       //6.获取消息
       while (true) {
           anInt += 1;
           QueueingConsumer.Delivery delivery1 = queueingConsumer1.nextDelivery(); 
           String message1 = String.valueOf(delivery1.getBody());          
           System.out.println("[" + String.valueOf(anInt) + "]:receve msg:" + message1);
           //手动确认ack  是否批量处理.true:将一次性ack所有小于deliveryTag的消息
           channel.basicAck(delivery1.getEnvelope().getDeliveryTag(), false);
           // System.out.println("[x] Received '" + message2 + "'");
           Thread.sleep(100);
       }
   }

效果图如下:
在这里插入图片描述
在这里插入图片描述
总共20条

(三):问题报错

1:Connection连接,监听队列时Queue队列设置和现在重新创建的队列的设置不一样。

'x-max-priority' for queue 'Hello-Queue1' in vhost '/': received none but current is the value '20'

解决办法:把之前创建的队列在RabbitMq Managment中删掉。

2:生产者和消费者创建队列设置不一致

Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - inequivalent arg 'durable' for queue 'Hello-Queue1' in vhost '/': received 'false' but current is 'true'

解决办法:把之前创建的队列在RabbitMq Managment中删掉。

总结:删除重置reset 万能的方法!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值