目录:

  • 细说交换器
  • 细说队列
  • 发送消息
  • 消费消息
  • 确认与拒绝

细说交换器:

1、方法:

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

autoDelete:自动删除;必须有解绑的动作,且需要全部解绑后交换器才会删除。

internal:内置路由器;客户端无法直接发送消息到交换器,只能通过交换器路由到内置路由器。

2、其他方法:

)不等待服务通知创建交换器命令:

public void exchangeDeclareNoWait(String exchange, String type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments) throws IOException

)检测交换器

public AMQP.Exchange.DeclareOk exchangeDeclarePassive(String name) throws IOException

)删除交换器

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

public void exchangeDeleteNoWait(String exchange, boolean ifUnused) throws IOException

public AMQP.Exchange.DeleteOk exchangeDelete(String exchange) throws IOException

ifUnused:为true,交换器没有被使用时删除这个交换器;为false,不管三七二十一直接删除这个交换器。

细说队列:

Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments) throws IOException;

队列主要介绍参数:boolean exclusiveboolean autoDeleteMap<String, Object> arguments

1、exclusive:排它性,true-排它,false-非排它。

设置为排它队列后,该队列只对首次声明它的连接可见,并在连接断开时自动删除;适用于一个客户端同时读写消息的场景。

 public class Product {

     private static final String EXCHANGE_NAME = "exclusive.exchange";
private static final String QUEUE_NAME = "exclusive.queue";
private static final String ROUTING_KEY_NAME = "exclusive.routing.key"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
Connection connection = RabbitMqUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
channel.queueDeclare(QUEUE_NAME, true, true, false, null);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTING_KEY_NAME);
channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN,
"排它队列".getBytes()); Connection connection2 = RabbitMqUtils.getConnection();
Channel channel2 = connection2.createChannel();
channel2.basicConsume(QUEUE_NAME, new DefaultConsumer(channel2) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.err.println("收到消息:" + new String(body));
}
}); // 线程休眠5秒,待消息回调完成
TimeUnit.SECONDS.sleep(5); RabbitMqUtils.close(connection, channel);
}
}

代码中18行用的是channel2,也就是connection2创建的信道,此时不满足排它队列的只允许首次创建它的连接使用,所以会抛出异常;将16行注释掉,17行的connection2替换成connection便能正常运行。

2、autoDelete:自动删除,true-自动删除,false-非自动删除。

设置为自动删除的队列后,该队列在其消费者都断开连接后,自动删除,不管队列里是否存在数据。

3、arguments:队列的其它参数。

前面几个参数很简单,我们这里只讲重点的x-dead-letter-exchangex-dead-letter-routing-key

 public class DeadProduct {

     private static final String EXCHANGE_NAME = "normal.exchange";
private static final String DEAD_EXCHANGE_NAME = "dead.exchange";
private static final String QUEUE_NAME = "normal.queue";
private static final String DEAD_QUEUE_NAME = "dead.queue";
private static final String ROUTING_KEY_NAME = "normal.routing.key";
private static final String DEAD_ROUTING_KEY_NAME = "dead.routing.key"; public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMqUtils.getConnection();
Channel channel = connection.createChannel(); channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
channel.exchangeDeclare(DEAD_EXCHANGE_NAME, BuiltinExchangeType.DIRECT); channel.queueDeclare(QUEUE_NAME, false, false, false, getArguments());
channel.queueDeclare(DEAD_QUEUE_NAME, false, false, false, null); channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTING_KEY_NAME);
channel.queueBind(DEAD_QUEUE_NAME, DEAD_EXCHANGE_NAME, ROUTING_KEY_NAME);
for (int i = 0; i < 10; i++) {
String message = "死信交换机" + i;
channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes());
} RabbitMqUtils.close(connection, channel);
} private static Map<String, Object> getArguments() {
Map<String, Object> result = new HashMap<String, Object>(5);
result.put("x-message-ttl", 5000);
result.put("x-dead-letter-exchange", DEAD_EXCHANGE_NAME);
result.put("x-dead-letter-routing-key", ROUTING_KEY_NAME);
return result;
}
}

x-dead-letter-exchange参数其实只是定义了一个交换机的名称,实际上你还需要定义一套mq的流程,如代码exchangeDeclare、queueDeclare、queueBind。

x-dead-letter-routing-key参数的routing-key需要与之前的路由key一致,否则数据将会匹配不到,也就不会走到DEAD_EXCHANGE_NAME里去了。

发送消息:

void basicPublish(String exchange, String routingKey, boolean mandatory, boolean immediate, BasicProperties props, byte[] body) throws IOException;

发送消息主要参数:mandatoryimmediate

1、mandatory:当消息无法路由到队列的处理方式。

2、immediate:当路由的队列无消费者时如何处理。

消费消息:

消费消息分为两种,一种是,一种是主动拉

1、推:basicConsumer(推,相当于监听,会消费调当前队列中所有的消息)

String basicConsume(String queue, boolean autoAck, String consumerTag, boolean noLocal, boolean exclusive, Map<String, Object> arguments, Consumer callback) throws IOException;

autoAck:是否自动确认,true-自动确认,false-非自动确认;当autoAck=true时,消费完时就会自动删除这条消息。

noLocal:设置为ture时,不能将同一个connection生产的消息在此connection消费,也就是说一个connection不能同时为生产者和消费者。

2、拉:basicGet(拉,只会拉取一条消息)

GetResponse basicGet(String queue, boolean autoAck) throws IOException;

注意:不能用for循环的basicGet代替basicConsumer,因为这样性能非常差。

确认与拒绝:

1、消息确认

)概念解释:

为了保证消息可靠的到达消费者,RabbitMQ提供了消息确认机制。

首先我们要知道除了手动的确认消息,还可以通过basicConsumer指定的autoAck参数来确认消息的到达。

autoAck=false时,RabbitMQ会显式的等待消息回复确认后才会将消息从内存或磁盘中移除(先设置为移除标记,然后在真正的移除);当autoAck=true时,RabbitMQ不管消费者有没有接收到消息,都会直接将消息移除。

注意:当RabbitMQ一直没有收到消费者确认消息的通知,并且消费者的连接断开时,那么此条消息会重新进入队列。

void basicAck(long deliveryTag, boolean multiple) throws IOException;

multiple:是否确认多条消息;true-确认多条(确认该信道上deliveryTag标记之前所有未经确认的消息),false-确认单条。

)代码示例:

 public class AckProduct {

     private static final String EXCHANGE_NAME = "ack.exchange";
private static final String QUEUE_NAME = "ack.queue";
private static final String ROUTING_KEY = "ack.routing-key"; public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMqUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTING_KEY); for (int i = 0; i < 20; i++) {
channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, null, ("ack" + i).getBytes());
} RabbitMqUtils.close(connection, channel);
}
}
 public class AckConsumer {

     private static final String QUEUE_NAME = "ack.queue";

     public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
Connection connection = RabbitMqUtils.getConnection();
final Channel channel = connection.createChannel(); // 因为basicConsumer会消费队列中所有的消息,这样不方便演示basicAck中multiple参数的效果,故用basicGet来消费消息
GetResponse getResponse = channel.basicGet(QUEUE_NAME, false);
System.err.println(getResponse.getEnvelope().getDeliveryTag() + ": " + new String(getResponse.getBody()));
System.err.println("-------------------------"); GetResponse getResponse2 = channel.basicGet(QUEUE_NAME, false);
System.err.println(getResponse2.getEnvelope().getDeliveryTag() + ": " + new String(getResponse2.getBody()));
System.err.println("-------------------------"); TimeUnit.SECONDS.sleep(10); GetResponse getResponse3 = channel.basicGet(QUEUE_NAME, false);
System.err.println(getResponse3.getEnvelope().getDeliveryTag() + ": " + new String(getResponse3.getBody()));
channel.basicAck(getResponse3.getEnvelope().getDeliveryTag(), false);
System.err.println("-------------------------"); // 休眠10秒,方便看到multiple参数的效果
TimeUnit.SECONDS.sleep(10); GetResponse getResponse4 = channel.basicGet(QUEUE_NAME, false);
System.err.println(getResponse4.getEnvelope().getDeliveryTag() + ": " + new String(getResponse4.getBody()));
channel.basicAck(getResponse4.getEnvelope().getDeliveryTag(), true); RabbitMqUtils.close(connection, channel);
}
}

首先AckProduct生产20条消息,AckConsumer先消费两条消息,再休眠10秒,此时可以看到ready为18,unacked为2,这两消息未确认(10 - 18行);

然后我们确认一条消息后,发现ready为17,unacked为2(20 - 23行);

此时便是关键时刻,若multiple真是如其定义一般,那么在执行28 - 30行后,ready应该是16,而未确认消息unacked应该是0才对,10秒后发现果然如此。

2、消息拒绝

)拒绝单条消息:

void basicReject(long deliveryTag, boolean requeue) throws IOException;

)拒绝多条消息:

void basicNack(long deliveryTag, boolean multiple, boolean requeue) throws IOException;

)参数说明:

multiple:是否拒绝多条消息;true-拒绝多条(拒绝该信道上deliveryTag标记之前所有未经确认的消息),false-拒绝单条(与basicAck类似)。

requeue:是否将拒绝的消息重新放入队列中;true-重新放入,false-丢弃。

RabbitMQ学习笔记(三、生产者与消费者)的更多相关文章

  1. RabbitMQ学习笔记三:Java实现RabbitMQ之与Spring集成

    搭建好maven项目环境,加入RabbitMQ依赖包 <dependency> <groupId>org.springframework.amqp</groupId> ...

  2. rabbitMQ学习笔记(三) 消息确认与公平调度消费者

    从本节开始称Sender为生产者 , Recv为消费者   一.消息确认 为了确保消息一定被消费者处理,rabbitMQ提供了消息确认功能,就是在消费者处理完任务之后,就给服务器一个回馈,服务器就会将 ...

  3. RabbitMQ学习笔记五:RabbitMQ之优先级消息队列

    RabbitMQ优先级队列注意点: 1.只有当消费者不足,不能及时进行消费的情况下,优先级队列才会生效 2.RabbitMQ3.5以后才支持优先级队列 代码在博客:RabbitMQ学习笔记三:Java ...

  4. 官网英文版学习——RabbitMQ学习笔记(一)认识RabbitMQ

    鉴于目前中文的RabbitMQ教程很缺,本博主虽然买了一本rabbitMQ的书,遗憾的是该书的代码用的不是java语言,看起来也有些不爽,且网友们不同人学习所写不同,本博主看的有些地方不太理想,为此本 ...

  5. RabbitMQ学习笔记1-hello world

    安装过程略过,一搜一大把. rabbitmq管理控制台:http://localhost:15672/   默认账户:guest/guest RabbitMQ默认监听端口:5672 JAVA API地 ...

  6. RabbitMQ学习笔记(五) Topic

    更多的问题 Direct Exchange帮助我们解决了分类发布与订阅消息的问题,但是Direct Exchange的问题是,它所使用的routingKey是一个简单字符串,这决定了它只能按照一个条件 ...

  7. 物联网学习笔记三:物联网网关协议比较:MQTT 和 Modbus

    物联网学习笔记三:物联网网关协议比较:MQTT 和 Modbus 物联网 (IoT) 不只是新技术,还是与旧技术的集成,其关键在于通信.可用的通信方法各不相同,但是,各种不同的协议在将海量“事物”连接 ...

  8. 官网英文版学习——RabbitMQ学习笔记(十)RabbitMQ集群

    在第二节我们进行了RabbitMQ的安装,现在我们就RabbitMQ进行集群的搭建进行学习,参考官网地址是:http://www.rabbitmq.com/clustering.html 首先我们来看 ...

  9. Oracle学习笔记三 SQL命令

    SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)  

  10. [Firefly引擎][学习笔记三][已完结]所需模块封装

    原地址:http://www.9miao.com/question-15-54671.html 学习笔记一传送门学习笔记二传送门 学习笔记三导读:        笔记三主要就是各个模块的封装了,这里贴 ...

随机推荐

  1. 关于python中的增量赋值的理解

    增量赋值运算符 += 和 *= 的表现取决于它们的第一个操作对象 += 操作首先会尝试调用对象的 __ iadd__方法,如果没有该方法,那么尝试调用__add__方法,所以+= 与 + 的区别实质是 ...

  2. django nginx 504 time-out 错误

    报错: 分析 nginx和uwsgi整合时有三个参数可以用于设置超时时间: 1.uwsgi_connect_timeout: 默认60秒,与uwsgi-server连接的超时时间,该值不能超过75秒. ...

  3. Dotnetcore安装nuget包时不能使用content中的文件

    问题:用NUGET打包了一个asp.netcore的项目,试图安装到另一个asp.netcore项目中,除了自动添加引用外,还希望自动释放一些文件以供修改.这些操作以前在netframe中是正常的,脚 ...

  4. web测试点集合

    转自:https://blog.csdn.net/yuki_ying/article/details/54946541 web测试点一 .界面检查 进入一个页面测试,首先是检查title,页面排版,字 ...

  5. fiddler 进行Android/IOS代理配置抓包

    1.准备:Android+IOS设备 下载:fiddler抓包工具,不是最新版的链接:   链接:https://pan.baidu.com/s/1BaBfu2H4xgpsh1wmkfC8aQ     ...

  6. 三feng云,免费虚拟主机和免费云服务器

    三feng云,免费虚拟主机和免费云服务器 链接:https://www.sanfengyun.com 虚拟主机 虚拟服务器 BGP多线路 独立IP地址 送免备案系统,永久免费 具备高在线率.高安全性. ...

  7. IT兄弟连 HTML5教程 CSS3揭秘 在HTML文档中放置CSS的几种方式

    有很多方法将样式表加入到HTML中,每种方法都有自己的优点和缺点.新的HTML元素和属性已被加入,以允许样式表与HTML文档更简易地组合起来.将样式表加入到HTML中的常用方法有内联样式表.嵌入一张样 ...

  8. python del和垃圾回收

    1. del是删除对象 2. python中的垃圾回收是删除引用计数

  9. PAT 1012 The Best Rank 排序

    To evaluate the performance of our first year CS majored students, we consider their grades of three ...

  10. RabbitMQ与Spring的框架整合之Spring Cloud Stream实战

    1.RabbitMQ与Spring Cloud Stream整合实战.SpringCloud Stream整体结构核心概念图,如下所示: 图示解释:Outputs输出,即消息的发送端.Inputs输入 ...