SpringBoot中配置延迟队列

SpringBoot中配置延迟队列

1.下载好对应的插件到rabbitmq中后添加依赖c3f4b2090b92c315aae2c91.png)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

此时如果通过UI界面可以看到延迟交换机类型 x-delayed-message

在这里插入图片描述

2.配置yaml

server:
  port: 8080
spring:
  application:
    # 微服务中会用到,养成好习惯加上。
    name: rabbitmq-test-delayDemo
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: admin
    password: admin
    virtual-host: /admin #有时候测试、上线、开发都用同一个队列,所以用virtual-host隔离开
    listener:
      simple:
        acknowledge-mode: manual #设置为手动回复的方式
    template:
      mandatory: true #强制调用回调函数
    publisher-returns: true
    publisher-confirm-type: CORRELATED #这个表示会调用confirm的回调函数

**关于回复方式:**自动回复的情况下即队列发送消息给消费者就返回ack,可能会造成消息丢失,例如如果消费者没有正确处理好消息。

3.配置MQConfig

@Configuration
public class RabbitMQConfig implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback  {
    private static final Logger logger= LoggerFactory.getLogger(RabbitMQConfig.class);
    public static final String LAZY_EXCHANGE="dingDanLYEXC";
    public static final String LAZY_QUEUE="dingDanLYQUE";
    public static final String LAZY_KEY="lazy.#";

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Bean
    public CustomExchange lazyExchange(){
        Map<String,Object> pros=new HashMap<String,Object>();
        pros.put("x-delayed-type","topic"); //指定交换机类型,Topic通配符模式
        CustomExchange exchange=new CustomExchange(LAZY_EXCHANGE,"x-delayed-message",true,false,pros) ;
//        exchange.setDelayed(true);
        //这和props.put("x-delayed-message","topic")是一样的。
        return exchange;
    }
    @Bean
    public Queue lazyQueue(){
        return new Queue(LAZY_QUEUE,true);
    }
    @Bean
    public Binding lazyBinding(){
        return BindingBuilder
                .bind(lazyQueue())
                .to(lazyExchange())
                .with(LAZY_KEY)
                .noargs();
    }

    @PostConstruct
    public void init(){
        rabbitTemplate.setMandatory(true);//声明了之后才会调用回调函数。
        rabbitTemplate.setConfirmCallback((RabbitTemplate.ConfirmCallback) this);
        rabbitTemplate.setReturnsCallback((RabbitTemplate.ReturnsCallback) this);
    }

    //不论消息是否可以找到对应的交换机都会回调。
    @Override
    public void confirm(CorrelationData correlationData, boolean b, String s) {
        logger.info("消息到交换机是否成功:"+b+" CorrelationData="+correlationData);
    }

    //消息从交换机到队列如果失败会回调此函数。
    @Override
    public void returnedMessage(ReturnedMessage returnedMessage) {
        logger.info("消息到队列是否成功");
    }
}

RabbitConfig实现了RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback接口的confirm方法和reuturnedMessage方法。

关于这两者返回的区别

  • ConfirmCallback:确认消息到达交换机,不论是否成功到达都会调用函数,以boolean b确认是否正确到达
  • returnedMessage:确认是否正常到达队列,如果没有到达则会调用此方法。

这两种机制是为了提高RabbitMQ的高可用。

4.配置生产者

@Component
public class MQSender{
    @Resource
    RabbitTemplate rabbitTemplate;

    public void sendLazy(Object message){
        CorrelationData correlationData=new CorrelationData("123"+new Date());
        rabbitTemplate.convertAndSend(RabbitMQConfig.LAZY_EXCHANGE, "lazy.boot", message, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //设置消息持久化
                message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                //设置延迟时间
                message.getMessageProperties().setDelay(6000);
                return message;
            }
        },correlationData);
    }

}

设置延迟时间还有另外一种方式,类似于pros中加"x-delay"

  • 关于CorrelationData: 是RabbitMQ的一种高级特性,主要作用是:因为在confirm和returnMessage机制中,为了避免消息丢失,需要给每个消息指定一个唯一的ID,就是CorrelationData

5.配置消费者

@Component
public class TopicConsumer {
    private static final Logger logger= LoggerFactory.getLogger(TopicConsumer.class);

    @RabbitHandler
    @RabbitListener(bindings={@QueueBinding(
            value=@Queue(value= RabbitMQConfig.LAZY_QUEUE,durable="true"),
            exchange=@Exchange(value=RabbitMQConfig.LAZY_EXCHANGE,durable="true",type="x-delayed-message"),
            key=RabbitMQConfig.LAZY_KEY)})
    public void consumer1(Channel channel, Message msg) throws IOException {
        logger.info("1--消费者收到的消息是:"+new String(msg.getBody()));
//        logger.info("路由key为"+msg.getMessageProperties().getReceivedRoutingKey());
//        logger.info("交换机为:"+msg.getMessageProperties().getReceivedExchange());
        long delTag=msg.getMessageProperties().getDeliveryTag();
        logger.info("1--消息id为:"+ delTag);
        logger.info("1--message的id为:"+msg.getMessageProperties().getMessageId());
        channel.basicAck(delTag,true);//正常确认,第二个参数multiple表示是否批量确认消息
    }

    @RabbitHandler
    @RabbitListener(bindings={@QueueBinding(
            value=@Queue(value=RabbitMQConfig.LAZY_QUEUE,durable="true"),
            exchange=@Exchange(value=RabbitMQConfig.LAZY_EXCHANGE,durable="true",type="x-delayed-message"),
            key=RabbitMQConfig.LAZY_KEY)})
    public void consumer2(Channel channel,Message msg) throws IOException {
        logger.info("2--消费者收到的消息是:"+new String(msg.getBody()));
//        logger.info("路由key为"+msg.getMessageProperties().getReceivedRoutingKey());
//        logger.info("交换机为:"+msg.getMessageProperties().getReceivedExchange());
        long delTag=msg.getMessageProperties().getDeliveryTag();
        logger.info("2--消息id为:"+ delTag);
        logger.info("2--message的id为:"+msg.getMessageProperties().getMessageId());
        channel.basicNack(delTag,true,false) ;//正常确认,第三个参数表示是否会返回队列中
    }
}
  • 消费者这里@RabbitListener中的一坨是为了保证如果消费者先运行的时候如果交换机和队列没有的话就创建
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值