1.POM 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2.配置交换机和队列绑定
package com.xx.rabbitmq.consume.mq.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMqAckConfig {
@Bean
public DirectExchange ackExchange() {
return new DirectExchange("ack.exchange");
}
@Bean
public Queue ackQueue() {
return QueueBuilder.durable("ack.queue")
.withArgument("x-dead-letter-exchange", "ack.error.exchange")
.withArgument("x-dead-letter-routing-key", "ack.error")
.build();
}
@Bean
public Binding ackBinding() {
return BindingBuilder.bind(ackQueue())
.to(ackExchange())
.with("ack.abc");
}
@Bean
public DirectExchange ackErrorExchange() {
return new DirectExchange("ack.error.exchange");
}
@Bean
public Queue ackErrorQueue() {
return QueueBuilder.durable("ack.error.queue").build();
}
@Bean
public Binding ackErrorBinding() {
return BindingBuilder.bind(ackErrorQueue())
.to(ackErrorExchange())
.with("ack.error");
}
}
3.消费端代码
package com.xx.rabbitmq.consume.mq.consume;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Slf4j
@Component
public class AckConsume {
private static final Logger ack_error_logger = LoggerFactory.getLogger("ack-error");
@Value("${spring.rabbitmq.listener.simple.retry.max-attempts}")
private Integer retryCountMax;
@RabbitListener(queues = {"ack.queue"})
public void simple1(String msg, Channel channel, Message message) throws IOException {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
log.info("----------------------消费者1 获取到消息: {}", msg);
System.out.println(1 / 0);
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
Map<String, Object> headers = message.getMessageProperties().getHeaders();
int retryCount = (int) headers.getOrDefault("x-retry-count", 1);
if (retryCount >= retryCountMax) {
channel.basicReject(deliveryTag, false);
} else {
headers.put("x-retry-count", retryCount + 1);
throw new RuntimeException("抛异常重试消息");
}
}
}
@RabbitListener(queues = {"ack.error.queue"})
public void ackError(String msg, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws IOException {
ack_error_logger.info("失败消息info:{}", msg);
channel.basicAck(deliveryTag, false);
}
}
4.application.yml 配置
server:
port: 8081
spring:
rabbitmq:
host: 111.111.111.111
port: 5672
virtual-host: my-host
username: admin
password: xxxxxx
listener:
simple:
prefetch: 1
acknowledge-mode: manual
retry:
enabled: true
initial-interval: 1000
max-attempts: 3
multiplier: 5
5. 生产者发送消息
rabbitTemplate.convertAndSend("ack.exchange", "ack.abc", "hello333");
运行结果
[2023-07-19 15:23:15.315] [] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1] INFO com.xx.rabbitmq.consume.mq.consume.AckConsume - [simple1,42] - ----------------------消费者1 获取到消息: hello333
[2023-07-19 15:23:16.316] [] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1] INFO com.xx.rabbitmq.consume.mq.consume.AckConsume - [simple1,42] - ----------------------消费者1 获取到消息: hello333
[2023-07-19 15:23:21.316] [] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1] INFO com.xx.rabbitmq.consume.mq.consume.AckConsume - [simple1,42] - ----------------------消费者1 获取到消息: hello333
[2023-07-19 15:23:21.328] [] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-1] INFO ack-error - [ackError,79] - 失败消息info:hello333