无法被消费的消息就是死信 消息被拒绝 消息ttl过期 队列达到最大长度 这三种场景就会成为死信,然后放入死信交换机 使用延时队列的场景; 1.说说发送定时任务; 2.会议预定开始前,提前提醒; 3.下单之后,10分钟内未支付; 4.发起退款,30分钟内未响应; 5.领导3天内没有审批; 6.预约成功后,30分钟内,没有签到; 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 RabbitmqConfig { //正常交换机的名字 public final static String EXCHANGE_NAME = "exchange_name"; //正常队列的名字 public final static String QUEUE_NAME="queue_name"; //死信交换机的名字 public final static String EXCHANGE_DEAD = "exchange_dead"; //死信队列的名字 public final static String QUEUE_DEAD="queue_dead"; //死信路由key public final static String DEAD_KEY="dead.key"; //创建正常交换机 @Bean(EXCHANGE_NAME) public Exchange exchange(){ return ExchangeBuilder.topicExchange(EXCHANGE_NAME) //持久化 mq重启后数据还在 .durable(true) .build(); } //创建正常队列 @Bean(QUEUE_NAME) public Queue queue(){ //正常队列和死信进行绑定 转发到 死信队列,配置参数 Map<String,Object>map=getMap(); return new Queue(QUEUE_NAME,true,false,false,map); } //正常队列绑定正常交换机 设置规则 执行绑定 定义路由规则 requestmaping映射 @Bean public Binding binding(@Qualifier(QUEUE_NAME) Queue queue, @Qualifier(EXCHANGE_NAME) Exchange exchange){ return BindingBuilder.bind(queue) .to(exchange) //路由规则 .with("app.#") .noargs(); } //创建死信队列 @Bean(QUEUE_DEAD) public Queue queueDead(){ return new Queue(QUEUE_DEAD,true,false,false); } //创建死信交换机 @Bean(EXCHANGE_DEAD) public Exchange exchangeDead(){ return ExchangeBuilder.topicExchange(EXCHANGE_DEAD) .durable(true) //持久化 mq重启后数据还在 .build(); } //绑定死信队列和死信交换机 @Bean public Binding deadBinding(){ return BindingBuilder.bind(queueDead()) .to(exchangeDead()) //路由规则 正常路由key .with(DEAD_KEY) .noargs(); } /** 获取死信的配置信息 * **/ public Map<String,Object>getMap(){ //3种方式 任选其一,选择其他方式之前,先把交换机和队列删除了,在启动项目,否则报错。 //方式一 Map<String,Object> map=new HashMap<>(16); //死信交换器名称,过期或被删除(因队列长度超长或因空间超出阈值)的消息可指定发送到该交换器中; map.put("x-dead-letter-exchange", EXCHANGE_DEAD); //死信消息路由键,在消息发送到死信交换器时会使用该路由键,如果不设置,则使用消息的原来的路由键值 map.put("x-dead-letter-routing-key", DEAD_KEY); //方式二 //消息的过期时间,单位:毫秒;达到时间 放入死信队列 // map.put("x-message-ttl",5000); //方式三 //队列最大长度,超过该最大值,则将从队列头部开始删除消息;放入死信队列一条数据 // map.put("x-max-length",3); return map; } }
配置文件信息
spring: rabbitmq: host: 192.168.23.135 port: 5672 username: admin password: admin #虚拟主机 virtual-host: dmg-a listener: simple: #自动ack acknowledge-mode: auto retry: #最大重试次数 max-attempts: 3 #开启重试 enabled: true
<!-- 引入 rabbitmq 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
生产者
@RestController @RequestMapping("p") public class TestController { @Autowired private RabbitTemplate rabbitTemplate; @GetMapping("/test") public String test(){ //正常交换机 正常路由键 正常消息内容 rabbitTemplate.convertAndSend(RabbitmqConfig.EXCHANGE_NAME ,"app.test","我是生产者"); return "aa"; } }
//消费者 @Component public class Xf { //监听正常队列名称 @RabbitListener(queues = {RabbitmqConfig.QUEUE_NAME}) public void normal(String payload, Message message, Channel channel) throws IOException { System.out.println("正常消息:"+payload); long tag=message.getMessageProperties().getDeliveryTag(); try{ // int i=1/0; //手动签收 channel.basicAck(tag,true); }catch (RuntimeException runtimeException){ //出现异常 删除消息 放入死信队列 channel.basicReject(tag,false); } } //监听死信队列名称 @RabbitListener(queues = {RabbitmqConfig.QUEUE_DEAD}) public void dead(String payload, Message message, Channel channel) throws IOException { System.out.println("死信队列:"+payload); //删除消息 放入数据库 人工处理 long deliveryTag=message.getMessageProperties().getDeliveryTag(); channel.basicAck(deliveryTag,true); } }