✨✨个人主页:沫洺的主页
📚📚系列专栏: 📖 JavaWeb专栏📖 JavaSE专栏 📖 Java基础专栏📖vue3专栏
📖MyBatis专栏📖Spring专栏📖SpringMVC专栏📖SpringBoot专栏
📖Docker专栏📖Reids专栏📖MQ专栏📖SpringCloud专栏
💖💖如果文章对你有所帮助请留下三连✨✨
这两种方式都是基于死信队列的基础进行的
//定义业务队列 @Bean public Queue directQueue() { return QueueBuilder.durable(QNAME) .deadLetterExchange(DENAME) //通过这两个配置,使我们的业务队列与死信交换机有关系了 .deadLetterRoutingKey(DKEY) .ttl(60*1000) //设置消息多久过期,消息超过这个时间就直接给死信交换机,让它处理 .maxLength(1000) //设置队列最大容量,超过这个容量就直接给死信交换机,让它处理 .build(); }简单来讲,就是通过ttl设置消息过期时间,消息队列没有消费者去应答,超过过期时间后,消息会进入死信队列,这个时候将死信队列就相当于延迟队列,监听死信队列,即可处理超时的消息队列
缺点:
这种方式,ttl延时队列中所有的消息超时时间都是一样的,如果不同消息想设置不一样的超时时间,就需要建立多个不同超时时间的消息队列,比较麻烦,且不利于维护。
rabbitTemplate.convertAndSend("交换机名称", "RoteingKey","对象",message => { //设置消息延迟时间5秒,5秒之后交给消费者,针对的是队列 message.getMessageProperties().setExpiration(String.valueOf(5000)) return message; } );相较于上面的ttl对所有消息设置过期时间而言,该方法可以针对某一条具体的消息设置延迟时间,当队列的ttl和setExpiration同时设置时,以最小的值为准
缺点:
该种方式可以创建一个承载不同超时时间消息的消息队列,但是这种方式有一个问题,如果消息队列中排在前面的消息没有到超时时间,即使后面的消息到了超时时间,先到超时时间的消息也不会进入死信队列,而是先检查排在最前面的消息队列是否到了超时时间,如果到了超时时间才会继续检查后面的消息,原理就是队列的先进先出.
补充:
这种对消息设置延迟时间的方式和通过延迟插件设置消息延迟时间的区别
//设置消息延迟时间5秒,5秒之后投递给队列 针对的是交换机 message.getMessageProperties().setDelay(5*1000); //设置消息延迟时间5秒,5秒之后交给消费者,针对的是队列 message.getMessageProperties().setExpiration(String.valueOf(5000));
- 延迟插件设置消息延迟是在交换机中进行的,延迟结束后传递给消息队列
- 而这种消息延迟是在消息队列中进行的,延迟结束后传递给死信队列
生产者最关心的两个点
- 生产者生产的消息有没有投递到交换机里
- 投递后交换机有没有将消息路由给队列
添加配置
#开启强制消息投递(mandatory为设置为true),但消息未被路由至任何一个queue, #则回退一条消息到RabbitTemplate.ReturnCallback中的returnedMessage方法: spring.rabbitmq.template.mandatory = true #开启交换机发布确认模式,交换机收到或者未收到消息, 都会调用回调实现类的回调确认方法 spring.rabbitmq.publisher-confirm-type=correlated #开启回退消息 , 当交换机无法将消息路由出去, 便会将消息回退给生产者 spring.rabbitmq.publisher-returns=true实现两个接口
- RabbitTemplate.ConfirmCallback
- 通过实现 ConfirmCallback 接口,消息发送到 Broker 后触发回调,确认消息是否到达 Broker 服务器,也就是只确认是否正确到达 Exchange 中。
- RabbitTemplate.ReturnsCallback
- 通过实现 ReturnCallback 接口,发送消息失败返回,比如路由不到队列时触发回调
模拟当没有交换机时
模拟当交互机存在,但没有队列时
补充:
在交换机确认回调函数中参数一: correlationData(相关数据)
在一些实际业务中会用到该参数,例如订单状态id等,通过状态id确认订单状态