版权声明:本文为博主原创文章,转载请注明出处 https://blog.csdn.net/love905661433/article/details/85256301
消费端ACK与重回队列
消费端ACK
- 消费端的手工ACK和NACK, ACK是确认成功消费, NACK表示消息处理失败, 会重发消息
- 消费端进行消费的时候, 如果由于业务异常我们可以进行日志的记录, 然后进行补偿
- 如果由于服务器宕机等严重问题, 就需要手工进行ACK保障消费端消费成功
重回队列
- 消费端重回队列是为了对没有处理成功的消息, 把消息重新回递给Broker
- 一般在实际应用中, 都会关闭重回队列, 也就是设置为False
代码演示
自定义消费者
package com.qiyexue.api.ack;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* 自定义消费者
* 设置手动ack和重回队列
* @author 七夜雪
* @date 2018-12-16 8:20
*/
public class MyConsumer extends DefaultConsumer {
private Channel channel;
public MyConsumer(Channel channel) {
super(channel);
this.channel = channel;
}
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("-------------自定义消费者------------");
System.out.println("consumerTag : " + consumerTag);
System.out.println("envelope : " + envelope);
System.out.println("properties : " + properties);
System.out.println("body : " + new String(body));
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
if ((Integer)properties.getHeaders().get("num") == 0) {
// 三个参数 : DeliveryTag, 是否批量拒绝, 是否可以重回队列
channel.basicNack(envelope.getDeliveryTag(), false, true);
} else {
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
}
Producer
package com.qiyexue.api.ack;
import com.rabbitmq.client.*;
import java.util.HashMap;
import java.util.Map;
/**
* 生产者
*
* @author 七夜雪
* @date 2018-12-15 19:56
*/
public class Producer {
public static void main(String[] args) throws Exception {
// 1. 创建ConnectionFactory, 并设置属性
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.72.138");
factory.setPort(5672);
factory.setVirtualHost("/");
// 2. 创建连接
Connection connection = factory.newConnection();
// 3. 创建channel
Channel channel = connection.createChannel();
String exchangeName = "test_ack_exchange";
String routingKey = "ack.qiye";
for (int i = 0; i < 5; i++) {
// 发送消息
String msg = "Hello, 七夜雪 " + i;
Map<String, Object> hearder = new HashMap<String, Object>();
hearder.put("num", i);
AMQP.BasicProperties properties = new AMQP.BasicProperties().builder()
.contentEncoding("UTF-8")
.headers(hearder).build();
channel.basicPublish(exchangeName, routingKey, true, properties, msg.getBytes());
}
// 关闭连接
channel.close();
connection.close();
}
}
Consumer
package com.qiyexue.api.ack;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* 消费者,关闭自动ack
*
* @author 七夜雪
* @date 2018-12-15 20:07
*/
public class Consumer {
public static void main(String[] args) throws Exception {
// 1. 创建连接工厂并设置属性
ConnectionFactory factory = new ConnectionFactory();;
factory.setHost("192.168.72.138");
factory.setPort(5672);
factory.setVirtualHost("/");
// 2. 创建连接
Connection connection = factory.newConnection();
// 3. 创建channel
Channel channel = connection.createChannel();
// 4. 声明Exchange
String exchangeName = "test_ack_exchange";
String exchangeType = "topic";
String routingKey = "ack.*";
channel.exchangeDeclare(exchangeName, exchangeType, true, false, null);
// 5. 声明消息队列
String queueName = "test_ack_queue";
channel.queueDeclare(queueName, true, false, false, null);
// 6. 绑定队列和Exchange
channel.queueBind(queueName, exchangeName, routingKey);
// 7. 设置消费者为自定义的消费者, 将autoAck设置为false
channel.basicConsume(queueName, false, new MyConsumer(channel));
}
}