交换器与队列
交换器
声明交换器
声明交换器参数说明:
参数 | 作用 |
---|---|
exchange | 交换器名称 |
type | 交换器类型,常见如fanout、direct、topic |
durable | 设置是否持久化 |
autoDelete | 设置是否自动删除 |
internal | 设置是否是内置 |
argument | 其他结构化参数 |
自动删除:自动删除的前提是至少有一个队列或者交换器与这个交换器绑定,之后所有与这个交换器绑定的队列或者交换器都与它解绑,才会自动删除交换器。必须有解除绑定这个动作,并且是在全部解绑之后。
内置路由器:客户端无法直接发送消息到内置交换器,只能通过交换器路由到内置路由器。
删除交换器
删除交换器时可指定ifUnused参数,来设置是否在交换器没有被使用的情况下删除。“没有被使用”指没有关联其他队列或交换器。
队列
声明队列
参数 | 作用 |
---|---|
queue | 队列名称 |
durable | 设置是否持久化 |
exclusive | 设置是否排他 |
autoDelete | 设置是否自动删除 |
argument | 设置队列的其他参数 |
排他队列:排他队列值仅对首次声明它的连接可见,并在连接断开时自动删除。
自动删除:当连接该队列的消费者都断开之后,队列删除,不管队列中是否有数据。
arguments参数说明:
参数 | 作用 |
---|---|
x-message-ttl | 消息过期时间,单位ms |
x-expires | 设置多长时间队列未使用,将被删除,单位ms |
x-max-length | 限定队列的消息的最大长度 |
x-max-length-bytes | 限定队列最大占用的空间大小,单位B |
x-dead-letter-exchange | 当队列消息长度大于最大长度、或者过期的等,将从队列中删除的消息推送到指定的交换器中 |
x-dead-letter-routing-key | 设置将删除的消息推送到指定交换器的路由键,不设置使用原来的路由键 |
x-max-priority | 优先级队列 |
x-queue-mode | 先将消息保存到磁盘上,不放在内存中,当消费者开始消费的时候才加载到内存中 |
注意:死信交换器、死信队列与普通交换器、普通队列没有区别,同样可以被其他消费者消费。
删除队列
删除队列时可指定ifEmpty参数,如果ifEmpty参数为true,则仅在队列为空的情况下才能被删除。
发送消息与消费消息
发送消息
使用Channel的basicPublish方法,向RabbitMQ发送消息。
(1) void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException;
(2) void basicPublish(String exchange, String routingKey, boolean mandatory, BasicProperties props, byte[] body) throws IOException;
(3) void basicPublish(String exchange, String routingKey, boolean mandatory, boolean immediate, BasicProperties props, byte[] body) throws IOException;
其中一些参数具体作用:
● exchange:交换器名称
● routingKey:路由键值
● props:消息的一些基本属性
● body:消息体
● mandatory与immediate:当消息无法路由到队列或者路由到的队列上没有消费者时,如何处理
消费消息
RabbitMQ消费消息分为两种模式:推(push)和拉(pull)。
推模式:
(1) String basicConsume(String queue, Consumer callback) throws IOException;
(2) String basicConsume(String queue, boolean autoAck, Consumer callback) throws IOException;
(3) String basicConsume(String queue, boolean autoAck, Map<String, Object> arguments, Consumer callback) throws IOException;
(4) String basicConsume(String queue, boolean autoAck, String consumerTag, Consumer callback) throws IOException;\
(5) String basicConsume(String queue, boolean autoAck, String consumerTag, boolean noLocal, boolean exclusive, Map<String, Object> arguments, Consumer callback) throws IOException;
其中一些参数具体作用:
- autoAck:是否自动确认,false表示不自动确认;
- consumerTag:消费者标签,用来区分多个消费者;
- noLocal:设置为true则表示不能将同一个Connection中生产者的消息传送 给这个Connection中的消费者;
- exclusive:设置是否排他;
- arguments:设置消费的其他参数;
- callback:设置消息的回调函数。用来处理RabbitMQ推送过来的消息
拉模式:
basicGet()单条获取消息,但basicGet不能用于for循环中代替basicConsume。
确认与拒绝
确认消息
客户端消费消息时,可以设置autoAck参数,当autoAck等于true时,RabbitMQ会自动把发送出去的消息改为确认,然后移除,而不管消息是否真正被消费者接收到。当autoAck等于false时,客户端需要调用basicAck()方法确认消费。
void basicAck(long deliveryTag, boolean multiple) throws IOException;
multiple为true时,确认消费该信道上deliveryTag之前的所有未确认的消息。
如果RabbitMQ一直没有收到消费者的确认信号,并且该消费者已经断开连接,则RabbitMQ会安排消息重新进入队列,等待投递给下一个消费者(可以是原消费者)。
拒绝消息
//拒绝单条消息
void basicReject(long deliveryTag, boolean requeue) throws IOException;
//拒绝多条消息
void basicNack(long deliveryTag, boolean multiple, boolean requeue) throws IOException;
路由失败处理
在发送消息channel.basicPublish方法中有两个参数分别是mandatory和immediate,它们都有当消息在传递过程中不可达目的地时,将消息返回给生产者的功能。RabbitMQ提供的备份交换器(Alternate Exchange)可以将未能被交换器路由的消息(没有绑定队列或者没有匹配的绑定)存储起来,而不用返回给客户端。
mandatory参数
当mandatory参数设为true时,如果交换器无法根据自身的类型和路由键找到一个符合条件的队列,那么RabbitMQ会调用Basic.Return命令将消息返回给生产者。当mandatory参数设置为false时,出现上述情形,则消息直接被丢弃。
immediate参数
当immediate参数设为true时,如果交换器在将消息路由到队列时发现队列上并不存在任何消费者,那么这条消息将不会存入队列中。当与路由键匹配的所有队列都没有消费者时,该消息会通过Basic.Return返回至生产者。
注意:RabbitMQ3.0版本开始去掉了该功能支持。官方解释:影响镜像队列的性能,增加代码复杂度。可以采用TTL+DLX代替
备份交换器
备份交换器可以将未被路由的消息存储在 RabbitMQ 中,再在需要的时候去处理这些消息。
关于备份交换器:
- 如果设置的备份交换器不存在,客户端和RabbitMQ服务端都不会出现异常,此时消息会丢失。
- 如果备份交换器没绑定任何队列,客户端和RabbitMQ服务端都不会出现异常,此时消息会丢失。
- 如备份交换器没任何匹配的队列,客户端和RabbitMQ服务端都不会出现异常,此时消息会丢失。
- 如果备份交换器和mandatory参数一起使用,如果备份交换器有效,那么mandatory参数无效 。
消息过期时间TTL
有两种方式可以设置消息的TTL:
- 设置队列属性值,队列中所有消息的过期时间都是相同的。
- 设置消息本身的过期时间,则可能队列中每条消息的过期时间不同。
对于第一中设置队列TTL属性的方式,一旦消息过期,就会从队列中抹除;而第二种方法,即使消息过期,也不一定会马上从队列中抹除。
why?
因为RabbitMQ并不会扫描整个队列的所有消息来判断消息的超时,等消息即将被消费的时候再判断即可,也就是当消息来到队列头部时。