[RabbitMq] 核心概念,原理与实战

1 特点

RabbitMQ是一个在AMQP基础上完成的,可复用的企业消息系统。它是一个高可用分布式集群技术,提供消息发布订阅,消息轨迹查询,定时(延时)消息,资源统计,监控报警等一系列消息云服务,是企业级互联网架构的核心产品。

2 使用场景

在项目中,将一些无需即时返回且耗时的操作提取出来,进行了异步处理,而这种异步处理的方式大大的节省了服务器的请求响应时间,从而提高了系统的吞吐量。

比如 : 秒杀抢购

3 作用

3.1 削峰限流

场景:秒杀活动,一般因为流量过大,导致应用挂掉,为了解决这个问题,一般在应用前端加入消息队列。

作用 : 可以控制活动人数,超过此一定阈值的订单直接丢弃;可以缓解短时间的高流量压垮应用(应用程序按自己的最大处理能力获取订单)

3.2 应用解耦

场景:用户下单后,订单系统需要通知库存系统,传统的做法就是订单系统调用库存系统的接口。这样当库存系统出现故障时,订单就会失败。

4 核心概念

Rabbitmq系统最核心的组件是Exchange和Queue,下图是系统简单的示意图。Exchange和Queue是在rabbitmq server(又叫做broker)端,producer和consumer在应用端。

Broker : 简单来说就是消息队列服务器实体。

Queue:消息队列载体,每个消息都会被投入到一个或多个队列。

     它提供了FIFO的处理机制,具有缓存消息的能力。rabbitmq中,队列消息可以设置为持久化,临时或者自动删除。

    1)设置为持久化的队列,queue中的消息会在server本地硬盘存储一份,防止系统crash,数据丢失;

    2)设置为临时队列,queue中的数据在系统重启之后就会丢失;

    3) 设置为自动删除的队列,当不存在用户连接到server,队列中的数据会被自动删除;

Exchange : 消息交换机,它指定消息按什么规则,路由到哪个队列。

    Rabbitmq中,producer不是通过信道直接将消息发送给Queue,而是先发送给Exchange。一个Exchange可以和多个Queue进行绑定,producer在传递消息的时候,会传递一个routing key,Exchange会根据这个 routing key 按照特定的路由算法,将消息路由给指定的Queue。和Queue一样,Exchange也可设置为持久化,临时或者自动删除。

    Exchange 有四种类型:direct(默认),fanout, topic, 和headers,不同类型的Exchange转发消息的策略有所区别:

    1) direct : 路由模式的交换器,Exchange会将消息发送到完全匹配 routing key 的Queue

    2) fanout : 广播是式交换器(发布/订阅模式),不管消息的 routing key设置为什么,Exchange都会将消息转发给所有绑定在其上的Queue。

    3) topic : 主题交换器,工作方式类似于组播,Exchange会将消息转发到和 routing key匹配模式相同的所有队列。比如:routing key 为user.stock的Message会转发给绑定匹配模式为 * .stock,user.stock, * . * 和#.user.stock.#的队列。( * 表是匹配一个任意词组,#表示匹配0个或多个词组)

    4) headers : 消息体的header匹配(ignore)。

Binding : 绑定,它的作用就是根据binding key把queue绑定到对应的exchange。 Exchange 和Queue的绑定可以是多对多的关系

virtual host :虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。(对应于数据库里的库)

producer:指的是消息生产者。

consumer :消息的消费者。

channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。

 

5 通信过程

    

6 实战

RabbitMQ 有五种工作模式,这也是实际使用RabbitMQ需要重点关注的,下面以实例来分析:

6.1 简单队列

一个生产者对应一个消费者

发送者

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class client {
    private final static String QUEUE_NAME = "hello";
    public static void main(String[] args) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.1.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        for(int i = 0; i < 100; i++){
            channel.basicPublish("",QUEUE_NAME, null, ("发送消息" + i).getBytes());
        }
        //关闭连接
        channel.close();
        connection.close();
    }
}

消费者:

import com.rabbitmq.client.*;
import java.io.IOException;

public class consumer {
    private static  final String QUEUE_NAME = "hello";
    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.1.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, 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收到内容是:" + new String(body));
                //确认
                channel.basicAck(envelope.getDeliveryTag(), false);//参数2,false为确认收到消息,true为拒绝收到消息
            }
        };
        /*
        注册消费者,参数2.代表我们收到消息后需要手动告诉服务器:我收到消息了
        true:表示自动确认,只要消息从队列中获取,无论消费者获取到消息后是否成功消费,都会认为消息已经成功消费
        false:表示手动确认,消费者获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,
            如果消费者一直没有反馈,那么该消息将一直处于不可用状态,并且服务器会认为该消费者已经挂掉,不会再给其
            发送消息,直到该消费者反馈。
         */
        channel.basicConsume(QUEUE_NAME, false, consumer);
    }
}

6.2 work模式

一个生产者对应多个消费者,每个消息只能被一个消费者获得。

生产者:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class client {
    private final static String QUEUE_NAME = "work_queue";
    public static void main(String[] args) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.1.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        for(int i = 0; i < 100; i++){
            String message = "hello rabbitmq "+i;
             //5、发布消息
             channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
             System.out.println("[x] Sent'"+message+"'");
            //模拟发送消息延时,便于演示多个消费者竞争接受消息
            Thread.sleep(i*10);
        }
        //关闭连接
        channel.close();
        connection.close();
    }
}

消费者 1:

import com.rabbitmq.client.*;
import java.io.IOException;

public class consumer {
    private static  final String QUEUE_NAME = "work_queue";
    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.0.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, 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收到内容是:" + new String(body));
                //消费者1接收一条消息后休眠10毫秒
                try {
                    Thread.sleep(10);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }

                //确认
                channel.basicAck(envelope.getDeliveryTag(), false);//参数2,false为确认收到消息,true为拒绝收到消息
            }
        };
        /*
        注册消费者,参数2.代表我们收到消息后需要手动告诉服务器:我收到消息了
        true:表示自动确认,只要消息从队列中获取,无论消费者获取到消息后是否成功消费,都会认为消息已经成功消费
        false:表示手动确认,消费者获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,
            如果消费者一直没有反馈,那么该消息将一直处于不可用状态,并且服务器会认为该消费者已经挂掉,不会再给其
            发送消息,直到该消费者反馈。
         */
        channel.basicConsume(QUEUE_NAME, false, consumer);
    }
}

消费者2:

import com.rabbitmq.client.*;
import java.io.IOException;

public class consumer2 {
    private static  final String QUEUE_NAME = "work_queue";
    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.1.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, 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收到内容是:" + new String(body));
                //消费者1接收一条消息后休眠1000毫秒
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }

                //确认
                channel.basicAck(envelope.getDeliveryTag(), false);//参数2,false为确认收到消息,true为拒绝收到消息
            }
        };
        /*
        注册消费者,参数2.代表我们收到消息后需要手动告诉服务器:我收到消息了
        true:表示自动确认,只要消息从队列中获取,无论消费者获取到消息后是否成功消费,都会认为消息已经成功消费
        false:表示手动确认,消费者获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,
            如果消费者一直没有反馈,那么该消息将一直处于不可用状态,并且服务器会认为该消费者已经挂掉,不会再给其
            发送消息,直到该消费者反馈。
         */
        channel.basicConsume(QUEUE_NAME, false, consumer);
    }
}

6.3 发布订阅模式(广播)

一个消费者将消息首先发送到交换机,交换机将消息发送到绑定在其上的所有队列。

PS:如果消息发送到没有队列绑定的交换器时,消息将丢失,因为交换器没有存储消息的能力,消息只能存储在队列中。

 

生产者:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class client {
    private final static String EXCHANGE_NAME = "fanout_exchange";
    public static void main(String[] args) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.1.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");//定义一个交换机,类型是fanout,也就是发布订阅模式
        //发布订阅模式的,因为消息是先发送到交换机中,而交换机是没有保存功能的,所以如果没有消费者,消息会丢失
        channel.basicPublish(EXCHANGE_NAME, "", null, "发布订阅模式的消息".getBytes());
        //关闭连接
        channel.close();
        connection.close();
    }
}

消费者1:

import com.rabbitmq.client.*;
import java.io.IOException;

public class consumer {
    private static  final String QUEUE_NAME = "fanout_queue_1";
    private final static String EXCHANGE_NAME = "fanout_exchange";
    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.1.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false,null);
        //绑定队列到交换机
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"");
        channel.basicQos(1);//告诉服务器,在我们没有确认当前消息完成之前,不要给我们发生消息
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者1收到内容是:" + new String(body));
                //消费者1接收一条消息后休眠10毫秒
                try {
                    Thread.sleep(10);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }

                //确认
                channel.basicAck(envelope.getDeliveryTag(), false);//参数2,false为确认收到消息,true为拒绝收到消息
            }
        };
        /*
        注册消费者,参数2.代表我们收到消息后需要手动告诉服务器:我收到消息了
        true:表示自动确认,只要消息从队列中获取,无论消费者获取到消息后是否成功消费,都会认为消息已经成功消费
        false:表示手动确认,消费者获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,
            如果消费者一直没有反馈,那么该消息将一直处于不可用状态,并且服务器会认为该消费者已经挂掉,不会再给其
            发送消息,直到该消费者反馈。
         */
        channel.basicConsume(QUEUE_NAME, false, consumer);
    }
}

消费者2:

import com.rabbitmq.client.*;
import java.io.IOException;

public class consumer2 {
    private static  final String QUEUE_NAME = "fanout_queue_2";
    private final static String EXCHANGE_NAME = "fanout_exchange";
    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.1.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false,null);
        //绑定队列到交换机
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"");
        channel.basicQos(1);//告诉服务器,在我们没有确认当前消息完成之前,不要给我们发生消息
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者2收到内容是:" + new String(body));
                //消费者1接收一条消息后休眠1000毫秒
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }

                //确认
                channel.basicAck(envelope.getDeliveryTag(), false);//参数2,false为确认收到消息,true为拒绝收到消息
            }
        };
        /*
        注册消费者,参数2.代表我们收到消息后需要手动告诉服务器:我收到消息了
        true:表示自动确认,只要消息从队列中获取,无论消费者获取到消息后是否成功消费,都会认为消息已经成功消费
        false:表示手动确认,消费者获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,
            如果消费者一直没有反馈,那么该消息将一直处于不可用状态,并且服务器会认为该消费者已经挂掉,不会再给其
            发送消息,直到该消费者反馈。
         */
        channel.basicConsume(QUEUE_NAME, false, consumer);
    }
}

6.4 路由模式:

生产者将消息发送到direct交换机,在绑定队列到交换机的时候有一个路由key,生产者发送的消息会指定一个路由key,那么消息只会发送到相应key相同的队列。

生产者:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class client {
    private final static String EXCHANGE_NAME = "direct_exchange";
    public static void main(String[] args) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.1.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");//定于路由模式的交换机
        channel.basicPublish(EXCHANGE_NAME,"orange", null, "路由模式消息1".getBytes());
        channel.basicPublish(EXCHANGE_NAME,"black", null, "路由模式消息2".getBytes());
        channel.basicPublish(EXCHANGE_NAME,"green", null, "路由模式消息3".getBytes());
        //关闭连接
        channel.close();
        connection.close();
    }
}

消费者1:

import com.rabbitmq.client.*;
import java.io.IOException;

public class consumer {
    private static  final String QUEUE_NAME = "direct_queue_1";
    private final static String EXCHANGE_NAME = "direct_exchange";
    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.1.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false,null);
        //绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "orange");
        channel.basicQos(1);//告诉服务器,在我们没有确认当前消息完成之前,不要给我们发生消息
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者1收到内容是:" + new String(body));
                //消费者1接收一条消息后休眠10毫秒
                try {
                    Thread.sleep(10);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }

                //确认
                channel.basicAck(envelope.getDeliveryTag(), false);//参数2,false为确认收到消息,true为拒绝收到消息
            }
        };
        /*
        注册消费者,参数2.代表我们收到消息后需要手动告诉服务器:我收到消息了
        true:表示自动确认,只要消息从队列中获取,无论消费者获取到消息后是否成功消费,都会认为消息已经成功消费
        false:表示手动确认,消费者获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,
            如果消费者一直没有反馈,那么该消息将一直处于不可用状态,并且服务器会认为该消费者已经挂掉,不会再给其
            发送消息,直到该消费者反馈。
         */
        channel.basicConsume(QUEUE_NAME, false, consumer);
    }
}

消费者2:

import com.rabbitmq.client.*;
import java.io.IOException;

public class consumer2 {
    private static  final String QUEUE_NAME = "direct_queue_2";
    private final static String EXCHANGE_NAME = "direct_exchange";
    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.1.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false,null);
        //绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "black");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "green");
        channel.basicQos(1);//告诉服务器,在我们没有确认当前消息完成之前,不要给我们发生消息
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者2收到内容是:" + new String(body));
                //消费者1接收一条消息后休眠1000毫秒
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }

                //确认
                channel.basicAck(envelope.getDeliveryTag(), false);//参数2,false为确认收到消息,true为拒绝收到消息
            }
        };
        /*
        注册消费者,参数2.代表我们收到消息后需要手动告诉服务器:我收到消息了
        true:表示自动确认,只要消息从队列中获取,无论消费者获取到消息后是否成功消费,都会认为消息已经成功消费
        false:表示手动确认,消费者获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,
            如果消费者一直没有反馈,那么该消息将一直处于不可用状态,并且服务器会认为该消费者已经挂掉,不会再给其
            发送消息,直到该消费者反馈。
         */
        channel.basicConsume(QUEUE_NAME, false, consumer);
    }
}

6.5 topic模式

路由模式是根据路由key进行完整的匹配(完全相等才发送消息),这里的通配符模式通俗的来讲就是模糊匹配。

  符号“#”表示匹配一个或多个词,符号“*”表示匹配一个词。

生产者:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class client {
    private final static String EXCHANGE_NAME = "topic_exchange";
    public static void main(String[] args) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.1.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");//定于topic模式的交换机
        channel.basicPublish(EXCHANGE_NAME,"key.1", null, "topic 模式消息1".getBytes());
        channel.basicPublish(EXCHANGE_NAME,"key.1.2", null, "topic 模式消息key.1.2".getBytes());
        channel.basicPublish(EXCHANGE_NAME,"abc.1.2", null, "topic 模式消息abc.1.2".getBytes());
        //关闭连接
        channel.close();
        connection.close();
    }
}

消费者1:

import com.rabbitmq.client.*;
import java.io.IOException;

public class consumer {
    private static  final String QUEUE_NAME = "topic_queue_1";
    private final static String EXCHANGE_NAME = "topic_exchange";
    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.1.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false,null);
        //绑定队列到交换机
        //参数3 标记,绑定到交换机的时候会指定一个标记,只有和它一样的标记的消息才会被当前消费者收到
        //topic 模式
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "key.*");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "abc.#");
        channel.basicQos(1);//告诉服务器,在我们没有确认当前消息完成之前,不要给我们发生消息
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者1收到内容是:" + new String(body));
                //消费者1接收一条消息后休眠10毫秒
                try {
                    Thread.sleep(10);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }

                //确认
                channel.basicAck(envelope.getDeliveryTag(), false);//参数2,false为确认收到消息,true为拒绝收到消息
            }
        };
        /*
        注册消费者,参数2.代表我们收到消息后需要手动告诉服务器:我收到消息了
        true:表示自动确认,只要消息从队列中获取,无论消费者获取到消息后是否成功消费,都会认为消息已经成功消费
        false:表示手动确认,消费者获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,
            如果消费者一直没有反馈,那么该消息将一直处于不可用状态,并且服务器会认为该消费者已经挂掉,不会再给其
            发送消息,直到该消费者反馈。
         */
        channel.basicConsume(QUEUE_NAME, false, consumer);
    }
}

消费者2:

import com.rabbitmq.client.*;
import java.io.IOException;

public class consumer2 {
    private static  final String QUEUE_NAME = "topic_queue_2";
    private final static String EXCHANGE_NAME = "topic_exchange";
    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.1.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false,null);
        //绑定队列到交换机
        //参数3 标记,绑定到交换机的时候会指定一个标记,只有和它一样的标记的消息才会被当前消费者收到
        //topic 模式
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "key.#");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "abc.#");
        channel.basicQos(1);//告诉服务器,在我们没有确认当前消息完成之前,不要给我们发生消息
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者2收到内容是:" + new String(body));
                //消费者1接收一条消息后休眠1000毫秒
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }

                //确认
                channel.basicAck(envelope.getDeliveryTag(), false);//参数2,false为确认收到消息,true为拒绝收到消息
            }
        };
        /*
        注册消费者,参数2.代表我们收到消息后需要手动告诉服务器:我收到消息了
        true:表示自动确认,只要消息从队列中获取,无论消费者获取到消息后是否成功消费,都会认为消息已经成功消费
        false:表示手动确认,消费者获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,
            如果消费者一直没有反馈,那么该消息将一直处于不可用状态,并且服务器会认为该消费者已经挂掉,不会再给其
            发送消息,直到该消费者反馈。
         */
        channel.basicConsume(QUEUE_NAME, false, consumer);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值