consumer side
Directory Structure
import dependencies
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.5.0</version>
</dependency>
</dependencies>
Modify yml
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
listener:
simple:
acknowledge-mode: auto
It can be seen that there are two types of listeners: direct and simple. The former is used for direct switches, while the latter is used for other switches
It can be seen that there are three modes of automatic confirmation mode: none, auto, manual.
acknowledge-mode: none means automatically acknowledge messages (default)
acknowledge-mode: manual means to manually acknowledge the message
acknowledge-mode: auto means to confirm the message according to the exception
Automatic confirmation means that once the message is received by the consumer, it will automatically confirm the receipt and remove the message from RabbitMQ's message cache. However, in the actual business, it is very likely that the message is received and the business processing is abnormal, then the message will be lost. If the manual confirmation method is adopted, it is necessary to call channel.basicACK() after the business processing is successful, and if an exception occurs, call channel.basicNack() to let it automatically resend the message.
Business logic
auto confirm
/**
* 消费者自动确认消息
* 1、yml中需要配置acknowledge-mode: none
* 2、消费者监听实现MessageListener
*/
@Component
public class AckListener implements MessageListener {
@RabbitListener(queues = "test_queue_name")
@Override
public void onMessage(Message message) {
System.out.println("消费者接受的消息为:" + new String(message.getBody()));
}
}
manual confirmation
/**
* 消费者手动确认消息
* 1、yml中需要配置acknowledge-mode: manual
* 2、消费者监听实现ChannelAwareMessageListener
*/
@Component
public class AckListener implements ChannelAwareMessageListener {
@RabbitListener(queues = "test_queue_name")
@Override
public void onMessage(Message message, Channel channel) throws Exception {
// 消息的唯一标识id
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
System.out.println("消费者接受的消息为:" + new String(message.getBody()));
// 手动签收的第一个参数为消息的唯一标识id、第二个参数表示是否批量签收
channel.basicAck(deliveryTag,true);
} catch (Exception e){
// 手动拒绝签收的第一个参数为消息id、第二个参数表示是否批量签收
// 第三个参数消息是否重回队列
channel.basicNack(deliveryTag,true,true);
System.out.println("消息被拒绝签收了");
}
}
}
/**
* 消费者手动确认消息
* 1、yml中需要配置acknowledge-mode: manual
* 2、消费者监听实现ChannelAwareMessageListener
*/
@Component
public class AckListener implements ChannelAwareMessageListener {
@RabbitListener(queues = "test_queue_name")
@Override
public void onMessage(Message message, Channel channel) throws Exception {
// 消息的唯一标识id
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
System.out.println("消费者接受的消息为:" + new String(message.getBody()));
int i = 1 / 0;//业务逻辑故意出错进入catch块
// 手动签收的第一个参数为消息的唯一标识id、第二个参数表示是否批量签收
channel.basicAck(deliveryTag,true);
} catch (Exception e){
// 手动拒绝签收的第一个参数为消息id、第二个参数表示是否批量签收
// 第三个参数消息是否重回队列
channel.basicNack(deliveryTag,true,true);
System.out.println("消息被拒绝签收了");
}
}
}
Note: the above terminal has an infinite loop because the third parameter of the channel.basicNack() method makes the message return to the queue for resend, but there is always a problem with the business logic block of try, so it will repeatedly report an error, if The third parameter is false and the result is as follows.