安装rabbitmq
下载docker镜像
docker pull rabbitmq:3-management
启动容器
docker run --name rabbitmq -p 5672:5672 -p 15672:15672 -d rabbitmq:3-management
查看容器
浏览器打开控制页面http://192.168.31.128:15672/#/ ip修改为自己虚拟机的ip,默认账号密码都是guest
springboot整合
依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.6.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.6.10</version>
</dependency>
</dependencies>
配置
server:
port: 8001
spring:
rabbitmq:
host: 192.168.31.128
port: 5672
username: guest
password: guest
virtual-host: /
Direct Exchange(直连交换机)
- 将消息发送到绑定键(binding key)与消息的路由键(routing key)完全匹配的队列。
- 可以理解为完全匹配模式。
- 通常用于点对点的消息传递。
这边要想接受到消息路由键就必须完全一样
上代码
配置类
RabbitConfigDirect.java
package com.cyz.config.direct;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitConfigDirect {
public static final String DIRECT_EXCHANGE = "cyz_direct_exchange";
public static final String QUEUE_INFORM_EMAIL = "cyz_direct_queue_email";
public static final String QUEUE_INFORM_SMS = "cyz_direct_queue_sms";
/**
* 通配符 * 表示一个单词 且必须出现
* 通配符 # 表示任意个单词 可以不出现
*/
public static final String ROUTING_KEY_EMAIL_DIRECT = "cyzEmail";
public static final String ROUTING_KEY_SMS_DIRECT = "zxxEmail";
//声明交换机
@Bean(DIRECT_EXCHANGE)
public Exchange directExchange() {
//durable(true) 持久化,mq重启之后交换机还在
return ExchangeBuilder.directExchange(DIRECT_EXCHANGE).durable(true).build();
}
@Bean(QUEUE_INFORM_EMAIL)
public Queue queueInformEmail() {
return new Queue(QUEUE_INFORM_EMAIL);
}
@Bean(QUEUE_INFORM_SMS)
public Queue queueInformSms() {
return new Queue(QUEUE_INFORM_SMS);
}
@Bean
public Binding bingingEmailToDirect(@Qualifier(QUEUE_INFORM_EMAIL) Queue queue,
@Qualifier(DIRECT_EXCHANGE) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY_EMAIL_DIRECT).noargs();
}
@Bean
public Binding bingingSmsToDirect(@Qualifier(QUEUE_INFORM_SMS) Queue queue,
@Qualifier(DIRECT_EXCHANGE) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY_SMS_DIRECT).noargs();
}
}
消费者
MessageReceiverDirect.java
package com.cyz.config.direct;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class MessageReceiverDirect {
@RabbitListener(queues = RabbitConfigDirect.QUEUE_INFORM_EMAIL)
public void receiveEmailMessage(String message) {
System.out.println("cyz_direct_queue_email Received Email message: " + message);
}
@RabbitListener(queues = RabbitConfigDirect.QUEUE_INFORM_SMS)
public void receiveSmsMessage(String message) {
System.out.println("cyz_direct_queue_sms Received Sms message: " + message);
}
}
生产者
MessageSenderDirect.java
package com.cyz.config.direct;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MessageSenderDirect {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendEmailMessage() {
rabbitTemplate.convertAndSend(RabbitConfigDirect.DIRECT_EXCHANGE, "email", "email");
rabbitTemplate.convertAndSend(RabbitConfigDirect.DIRECT_EXCHANGE, "cyzEmail", "cyzEmail");
rabbitTemplate.convertAndSend(RabbitConfigDirect.DIRECT_EXCHANGE, "zxxEmail", "zxxEmail");
}
}
测试
发送了三个,只收到了两个,所以直连的路由键必须一样才能匹配成功
Fanout Exchange(扇形交换机)
- 将消息广播到所有绑定到该交换机上的队列。
- 忽略消息的路由键,直接将消息发送给所有绑定的队列。
- 通常用于一对多的消息广播。
扇形交换机会把所有的消息广播到与它绑定的所有队列,这边的路由键已经不起作用了
上代码
配置类
RabbitConfigFanout.java
package com.cyz.config.fanout;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitConfigFanout {
public static final String FANOUT_EXCHANGE = "cyz_fanout_exchange";
public static final String QUEUE_INFORM_EMAIL = "cyz_fanout_queue_email";
public static final String QUEUE_INFORM_SMS = "cyz_fanout_queue_sms";
/**
* 通配符 * 表示一个单词 且必须出现
* 通配符 # 表示任意个单词 可以不出现
*/
public static final String ROUTING_KEY_EMAIL_FANOUT = "cyzEmail";
public static final String ROUTING_KEY_SMS_FANOUT = "zxxEmail";
//声明交换机
@Bean(FANOUT_EXCHANGE)
public Exchange directExchange() {
//durable(true) 持久化,mq重启之后交换机还在
return ExchangeBuilder.fanoutExchange(FANOUT_EXCHANGE).durable(true).build();
}
@Bean(QUEUE_INFORM_EMAIL)
public Queue queueInformEmail() {
return new Queue(QUEUE_INFORM_EMAIL);
}
@Bean(QUEUE_INFORM_SMS)
public Queue queueInformSms() {
return new Queue(QUEUE_INFORM_SMS);
}
@Bean
public Binding bingingEmailToFanout(@Qualifier(QUEUE_INFORM_EMAIL) Queue queue,
@Qualifier(FANOUT_EXCHANGE) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY_EMAIL_FANOUT).noargs();
}
@Bean
public Binding bingingSmsToFanout(@Qualifier(QUEUE_INFORM_SMS) Queue queue,
@Qualifier(FANOUT_EXCHANGE) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY_SMS_FANOUT).noargs();
}
}
消费者
MessageReceiverFanout.java
package com.cyz.config.fanout;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class MessageReceiverFanout {
@RabbitListener(queues = RabbitConfigFanout.QUEUE_INFORM_EMAIL)
public void receiveEmailMessage(String message) {
System.out.println("cyz_fanout_queue_email Received Email message: " + message);
}
@RabbitListener(queues = RabbitConfigFanout.QUEUE_INFORM_SMS)
public void receiveSmsMessage(String message) {
System.out.println("cyz_fanout_queue_sms Received Sms message: " + message);
}
}
生产者
MessageSenderFanout.java
package com.cyz.config.fanout;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MessageSenderFanout {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendEmailMessage() {
rabbitTemplate.convertAndSend(RabbitConfigFanout.FANOUT_EXCHANGE, "email", "email");
rabbitTemplate.convertAndSend(RabbitConfigFanout.FANOUT_EXCHANGE, "cyzEmail", "cyzEmail");
rabbitTemplate.convertAndSend(RabbitConfigFanout.FANOUT_EXCHANGE, "zxxEmail", "zxxEmail");
}
}
测试
由结果可知,即使路由键不匹配也会收到消息
Topic Exchange(主题交换机)
- 根据消息的路由键和绑定键之间的模式匹配规则,将消息发送到一个或多个符合条件的队列。
- 绑定键可以使用通配符进行模式匹配。
- 通常用于灵活的消息路由和订阅发布的场景。
这里通配符有两种:
一个是*(有且只有一个单词) 例如*.sms.*,匹配的字符串只可以类似aa.sms.bb类型的,像aa.aa.sms.bb、aa.sms.bb.bb、sms.aa、aa.sms等都不会匹配成功
一个是#(可以匹配任意个单词,可以是零个单词) 例如#.sms.#,匹配的字符串只可以类似aa.sms.bb、aa.aa.sms.bb、aa.sms.bb.bb、sms.aa、aa.sms、sms等
上代码
配置类
RabbitConfigTopic.java
package com.cyz.config;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitConfigTopic {
public static final String TOPIC_EXCHANGE = "cyz_topic_exchange";
public static final String QUEUE_INFORM_EMAIL1 = "cyz_topic_queue_email1";
public static final String QUEUE_INFORM_EMAIL2 = "cyz_topic_queue_email2";
public static final String QUEUE_INFORM_SMS = "cyz_topic_queue_sms";
/**
* 通配符 * 表示一个单词 且必须出现
* 通配符 # 表示任意个单词 可以不出现
*/
public static final String ROUTING_KEY_EMAIL_TOPIC1 = "#.email.#";
public static final String ROUTING_KEY_EMAIL_TOPIC2 = "*.email.*";
public static final String ROUTING_KEY_SMS_TOPIC = "#.sms.#";
//声明交换机
@Bean(TOPIC_EXCHANGE)
public Exchange topicExchange() {
//durable(true) 持久化,mq重启之后交换机还在
return ExchangeBuilder.topicExchange(TOPIC_EXCHANGE).durable(true).build();
}
@Bean(QUEUE_INFORM_EMAIL1)
public Queue queueInformEmail1() {
return new Queue(QUEUE_INFORM_EMAIL1);
}
@Bean(QUEUE_INFORM_EMAIL2)
public Queue queueInformEmail2() {
return new Queue(QUEUE_INFORM_EMAIL2);
}
@Bean(QUEUE_INFORM_SMS)
public Queue queueInformSms() {
return new Queue(QUEUE_INFORM_SMS);
}
@Bean
public Binding bingingEmailToTopic1(@Qualifier(QUEUE_INFORM_EMAIL1) Queue queue,
@Qualifier(TOPIC_EXCHANGE) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY_EMAIL_TOPIC1).noargs();
}
@Bean
public Binding bingingEmailToTopic2(@Qualifier(QUEUE_INFORM_EMAIL2) Queue queue,
@Qualifier(TOPIC_EXCHANGE) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY_EMAIL_TOPIC2).noargs();
}
@Bean
public Binding bingingSmsToTopic(@Qualifier(QUEUE_INFORM_SMS) Queue queue,
@Qualifier(TOPIC_EXCHANGE) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY_SMS_TOPIC).noargs();
}
}
消费者
MessageReceiverTopic.java
package com.cyz.config;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class MessageReceiverTopic {
@RabbitListener(queues = RabbitConfigTopic.QUEUE_INFORM_EMAIL1)
public void receiveEmailMessage1(String message) {
System.out.println("cyz_topic_queue_email1 Received Email message: " + message);
}
@RabbitListener(queues = RabbitConfigTopic.QUEUE_INFORM_EMAIL2)
public void receiveEmailMessage2(String message) {
System.out.println("cyz_topic_queue_email2 Received Email message: " + message);
}
@RabbitListener(queues = RabbitConfigTopic.QUEUE_INFORM_SMS)
public void receiveSmsMessage(String message) {
System.out.println("cyz_topic_queue_sms Received Sms message: " + message);
}
}
生产者
MessageSenderTopic.java
package com.cyz.config;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MessageSenderTopic {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendEmailMessage() {
rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"email", "email");
rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"hello.email", "hello.email");
rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"email.cyz", "email.cyz");
rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"hello.email.cyz", "hello.email.cyz");
rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"hello.email.cyz.zxx", "hello.email.cyz.zxx");
rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"zxx.hello.email.cyz", "zxx.hello.email.cyz");
rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"zxx.hello.email.cyz.zxx", "zxx.hello.email.cyz.zxx");
}
public void sendSmsMessage(String message) {
rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"hello.sms.cyz", message);
}
}
测试
结果如下
又结果可知通配符的匹配规则,主题类型的交换机只要符合路由键规则就能匹配成功,接收到消息
Headers Exchange(头交换机)
- 在消息头部的键值对进行匹配,根据匹配结果将消息发送给一个或多个队列。
- 可以通过自定义规则进行复杂的匹配操作。
- 通常用于消息头部信息匹配的场景。
只有指定情况下才可以匹配成功,例如Header里面必须有name且值为张三,那就只有消息中带有这个Header且值为张三的才能匹配,可以是多个值,必须全部匹配
上代码
配置类
RabbitConfigHeader.java
package com.cyz.config.header;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class RabbitConfigHeader {
public static final String HEADER_EXCHANGE = "cyz_header_exchange";
public static final String QUEUE_INFORM_EMAIL = "cyz_header_queue_email";
//声明交换机
@Bean(HEADER_EXCHANGE)
public Exchange headerExchange() {
return ExchangeBuilder.headersExchange(HEADER_EXCHANGE).durable(true).build();
}
@Bean(QUEUE_INFORM_EMAIL)
public Queue queueInformEmail() {
return new Queue(QUEUE_INFORM_EMAIL);
}
@Bean
public Binding bingingEmailToHeader(@Qualifier(QUEUE_INFORM_EMAIL) Queue queue,
@Qualifier(HEADER_EXCHANGE) Exchange exchange) {
Map<String, Object> headers = new HashMap<>();
headers.put("name", "cyz");
headers.put("age", "25");
return BindingBuilder.bind(queue).to(exchange).with("").and(headers);
}
}
消费者
MessageReceiverHeader.java
package com.cyz.config.header;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class MessageReceiverHeader {
@RabbitListener(queues = RabbitConfigHeader.QUEUE_INFORM_EMAIL)
public void receiveEmailMessage(String message) {
System.out.println("cyz_fanout_queue_email Received Email message: " + message);
}
}
生产者
MessageSenderHeader.java
package com.cyz.config.header;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MessageSenderHeader {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendEmailMessage() {
String msg="hello1";
MessageProperties messageProperties1 = new MessageProperties();
messageProperties1.setHeader("name","cyz");
messageProperties1.setHeader("age","25");
Message message1 = new Message(msg.getBytes(),messageProperties1);
rabbitTemplate.convertAndSend(RabbitConfigHeader.HEADER_EXCHANGE, null, message1);
String msg2="hello2";
MessageProperties messageProperties2 = new MessageProperties();
messageProperties2.setHeader("name1","cyz");
messageProperties2.setHeader("age","25");
Message message2 = new Message(msg2.getBytes(),messageProperties2);
rabbitTemplate.convertAndSend(RabbitConfigHeader.HEADER_EXCHANGE, null, message2);
String msg3="hello3";
MessageProperties messageProperties3 = new MessageProperties();
messageProperties3.setHeader("name1","cyz");
messageProperties3.setHeader("age1","25");
Message message3 = new Message(msg3.getBytes(),messageProperties3);
rabbitTemplate.convertAndSend(RabbitConfigHeader.HEADER_EXCHANGE, null, message3);
}
}
测试
只匹配了一个
延时队列
消息延时
public class RabbitConfig_SLA {
/**
* 处理sla交换机名称
*/
public final static String EXCHANGE_SLA_NAME = "tt_sla_task_exchange";
/**
* 处理过期任务队列
*/
public final static String SLA_EXPIRE_TASK_QUEUE_NAME = "tt_sla_expire_task_queue";
/**
* 处理超时任务队列名称
*/
public final static String SLA_TIMEOUT_TASK_QUEUE_NAME = "tt_sla_timeout_task_queue";
/**
* 过期路由
*/
public final static String SLA_EXPIRE_TASK_KEY = "tt_sla_expire_task_key";
/**
* 超时路由
*/
public final static String SLA_TIMEOUT_TASK_KEY = "tt_sla_timeout_task_key";
@Bean(SLA_EXPIRE_TASK_QUEUE_NAME)
public Queue expireQueue() {
return QueueBuilder.durable(SLA_EXPIRE_TASK_QUEUE_NAME).build();
}
@Bean(SLA_TIMEOUT_TASK_QUEUE_NAME)
public Queue timeoutQueue() {
return QueueBuilder.durable(SLA_TIMEOUT_TASK_QUEUE_NAME).build();
}
@Bean(EXCHANGE_SLA_NAME)
public Exchange exchange() {
Map<String, Object> args = new HashMap<>();
args.put("x-delayed-type", "direct");
return new CustomExchange(EXCHANGE_SLA_NAME, "x-delayed-message", true, false, args);
}
@Bean
public Binding bindingExpire(@Qualifier(SLA_EXPIRE_TASK_QUEUE_NAME) Queue queue, @Qualifier(EXCHANGE_SLA_NAME) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(SLA_EXPIRE_TASK_KEY).noargs();
}
@Bean
public Binding bindingTimeout(@Qualifier(SLA_TIMEOUT_TASK_QUEUE_NAME) Queue queue, @Qualifier(EXCHANGE_SLA_NAME) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(SLA_TIMEOUT_TASK_KEY).noargs();
}
}
private Message buildMessage(SendMsgTemplate sendMsgTemplate, long time) {
int delayTime = (int) (time - System.currentTimeMillis());
if (delayTime < 0) {
delayTime = 0;
}
Message message = new Message(JSONObject.toJSONString(sendMsgTemplate).getBytes());
message.getMessageProperties().setDelay(delayTime);
return message;
}
public void sendSlaExpireMq(SendMsgTemplate sendMsgTemplate) {
log.info("enter sendSlaExpireMq {}", sendMsgTemplate);
rabbitTemplate.convertAndSend(RabbitConfig_SLA.EXCHANGE_SLA_NAME, RabbitConfig_SLA.SLA_EXPIRE_TASK_KEY, buildMessage(sendMsgTemplate, sendMsgTemplate.getExpireTime()));
log.info("finish sendSlaExpireMq {}", sendMsgTemplate);
}
死信队列
创建两个队列和两个交换机如下,通过死信队列实现延时队列功能
上代码
配置类
RabbitConfigDelay.java
package com.cyz.config.delayqueue;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@Configuration
public class RabbitConfigDelay {
public static final String DELAY_EXCHANGE = "cyz_delay_exchange";
public static final String NORMAL_EXCHANGE = "cyz_normal_exchange";
public static final String DELAY_QUEUE = "cyz_delay_queue";
public static final String NORMAL_QUEUE = "cyz_normal_queue";
public static final String DELAY_KEY = "cyz_delay_key";
public static final String NORMAL_KEY = "cyz_normal_key";
//声明交换机
@Bean(DELAY_EXCHANGE)
public Exchange delayExchange() {
return ExchangeBuilder.directExchange(DELAY_EXCHANGE).build();
}
@Bean(NORMAL_EXCHANGE)
public Exchange normalExchange() {
return ExchangeBuilder.directExchange(NORMAL_EXCHANGE).build();
}
@Bean(DELAY_QUEUE)
public Queue delayQueue() {
/**
* 消息发送给延时队列
* 设置延时队列的过期时间为5秒钟
* 5秒之后,延时队列将消息发送给普通队列
*/
Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", NORMAL_EXCHANGE);
args.put("x-dead-letter-routing-key", NORMAL_KEY);
args.put("x-message-ttl", 5000);
return QueueBuilder.durable(DELAY_QUEUE).withArguments(args).build();
}
@Bean(NORMAL_QUEUE)
public Queue normalQueue() {
return QueueBuilder.durable(NORMAL_QUEUE).build();
}
@Bean
public Binding bingingToDelay(@Qualifier(DELAY_QUEUE) Queue queue,
@Qualifier(DELAY_EXCHANGE) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(DELAY_KEY).noargs();
}
@Bean
public Binding bingingToNormal(@Qualifier(NORMAL_QUEUE) Queue queue,
@Qualifier(NORMAL_EXCHANGE) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(NORMAL_KEY).noargs();
}
}
消费者
MessageReceiverDelay.java
package com.cyz.config.delayqueue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class MessageReceiverDelay {
@RabbitListener(queues = RabbitConfigDelay.NORMAL_QUEUE)
public void receiveEmailMessage(String message) {
System.out.println(System.currentTimeMillis());
System.out.println("cyz_delay_queue_email Received Email message: " + message);
}
}
生产者
MessageSenderDelay.java
package com.cyz.config.delayqueue;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MessageSenderDelay {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendEmailMessage() {
System.out.println(System.currentTimeMillis());
rabbitTemplate.convertAndSend(RabbitConfigDelay.DELAY_EXCHANGE, RabbitConfigDelay.DELAY_KEY,"delay");
}
}
测试
上面配置的时间是5秒,这边刚好差5秒
消息确认及设置重试次数
@RabbitListener(queues = RabbitConfig_SLA.SLA_TIMEOUT_TASK_QUEUE_NAME)
private void consumerTimeoutTask(Message message, Channel channel) throws Exception {
//先转换消息为对象
SendMsgTemplate sendMsgTemplate = JSONObject.parseObject(new String(message.getBody()), SendMsgTemplate.class);
log.info("enter consumerTimeoutTask {}", sendMsgTemplate);
try {
consumeTimeoutTask(sendMsgTemplate);
//确认消息
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
log.info("finish consumerTimeoutTask {}", sendMsgTemplate);
} catch (IOException e) {
//消费失败重新入队
log.error("consumerTimeoutTask error {}", sendMsgTemplate);
handleException(message, channel);
}
}
/**
* 处理异常,如果重试次数达到最大重试次数就直接确认消息
*/
private void handleException(Message message, Channel channel) throws Exception {
// 处理消息处理失败的逻辑
int retryCount = getRetryCount(message);
channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
if (retryCount < 3) {
// 重新入队列,增加重试次数
message.getMessageProperties().getHeaders().put("retryCount", ++retryCount);
rabbitTemplate.convertAndSend(RabbitConfig_SLA.EXCHANGE_SLA_NAME, RabbitConfig_SLA.SLA_TIMEOUT_TASK_KEY, message);
} else {
// 超过最大重试次数
log.warn("Max retry count reached,discard the message {}", message.getMessageProperties().getDeliveryTag());
}
}
/**
* 获取重试了次数
*/
private int getRetryCount(Message message) {
// 从消息头中获取重试次数
Integer retryCount = message.getMessageProperties().getHeader("retryCount");
return retryCount != null ? retryCount : 0;
}