消費者側
ディレクトリ構造
依存関係のインポート
<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>
yml を変更する
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
listener:
simple:
acknowledge-mode: auto
直接リスナーと単純リスナーの 2 種類のリスナーがあることがわかります。前者は直接スイッチに使用され、後者は他のスイッチに使用されます。
自動確認モードには、none、auto、manual の 3 つのモードがあることがわかります。
確認モード: none は自動的にメッセージを確認することを意味します (デフォルト)
確認モード: 手動でメッセージを確認する手段
確認モード: 自動は、例外に従ってメッセージを確認することを意味します
自動確認とは、コンシューマーがメッセージを受信すると、受信を自動的に確認し、RabbitMQ のメッセージ キャッシュからメッセージを削除することを意味します。しかし、実際の業務では、メッセージが受信されて業務処理が異常になり、メッセージが失われる可能性が非常に高くなります。手動確認方式の場合、業務処理成功後にchannel.basicACK()を呼び出し、例外が発生した場合はchannel.basicNack()を呼び出してメッセージを自動再送させる必要があります。
ビジネスの論理
自動確認
/**
* 消费者自动确认消息
* 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()));
}
}
手動確認
/**
* 消费者手动确认消息
* 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("消息被拒绝签收了");
}
}
}
注: 上記の端末は、channel.basicNack() メソッドの 3 番目のパラメーターによってメッセージが再送信のためにキューに戻されるため、無限ループが発生しますが、try のビジネス ロジック ブロックには常に問題があるため、繰り返し報告されます。 3 番目のパラメータが false で、結果が次の場合はエラー。