springboot 与rabbitmq集成+生产者投递确认+消费者手动确认+TTL+死信队列+延时队列

1 篇文章 0 订阅
1 篇文章 0 订阅

1、生产者的消息可靠性投递机制
1)springboot yml文件配置

spring:
  rabbitmq:
    host: 10.0.23.83
    username: lifwe
    password: 123456
    virtual-host: amq123
    port: 5672
    publisher-confirm-type: correlated #类型设置为correlate 
    publisher-returns: true #需要设置weitrue
    template:
      mandatory: true #设置交换机处理失败消息的模式需要设置为true

2)rabbit exchange和queue配置类

package com.rabbitmq.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;

/**
 * @author lifwe
 * @version 1.0
 * @ClassName :RabbitMqConfig
 * @Description :
 * @date 2021/3/17 10:53
 */
@Configuration
public class RabbitMqConfig {

    public static final String MQ_EXCHANGE = "boot_exchange";

    public static final String MQ_QUEUE = "boot_queue";

    @Bean("mqExchange")
    public Exchange getMqExchange(){
        return ExchangeBuilder.directExchange(MQ_EXCHANGE).durable(true).build();
    }

    @Bean("mqQueue")
    public Queue getQueue(){
        return QueueBuilder.durable(MQ_QUEUE).build();
    }

    @Bean
    public Binding getBinding(@Qualifier("mqExchange") Exchange exchange , @Qualifier("mqQueue") Queue queue){
        return BindingBuilder.bind(queue).to(exchange).with("info").noargs();

    }
}

3)验证测试Test类

package com.rabbitmq.springbootrabbitmq;

import org.junit.runner.RunWith;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @author lifwe
 * @version 1.0
 * @ClassName :Test
 * @Description :
 * @date 2021/3/17 11:10
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class Test {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * @Author lifwe
     * @Description 测试exchange消息投递方法
     * @Date 11:32 2021/3/17
     * @Param []
     * @return void
     **/
    @org.junit.Test
    public void test() throws InterruptedException {
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean b, String s) {
                if(b){
                    System.out.println("exchange接收消息成功!");
                }else{
                    System.out.println("exchange接收消息失败!");
                }
            }
        });
        rabbitTemplate.convertAndSend("boot_exchange","info","springboot 测试confirm");
        Thread.sleep(3000);
    }

    /**
     * @Author lifwe
     * @Description 测试queue消息投递方法
     * @Date 11:32 2021/3/17
     * @Param []
     * @return void
     **/
    @org.junit.Test
    public void test2() throws InterruptedException {
        rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
            @Override
            public void returnedMessage(ReturnedMessage returnedMessage) {
                System.out.println(returnedMessage.getReplyText());
            }
        });
        rabbitTemplate.convertAndSend("boot_exchange","info1","springboot 测试confirm");
        Thread.sleep(3000);
    }

}

4)查看结果

当将routing key 故意写错时,会进入回调方法,只有当消息投递queue失败时,才会进入回调方法

2、消费者手动确认机制
1)yml文件配置

spring:
  rabbitmq:
    host: 10.0.23.83
    username: lifwe
    password: 123456
    virtual-host: amq123
    port: 5672
    listener:
      direct:
        acknowledge-mode: manual
      simple:
        acknowledge-mode: manual

2)监听代码

@Component
public class RabbitMqListener {

    @RabbitListener(queues="boot_queue")
    public void getRabbitMqMessage(Message message, Channel channel) throws IOException {
        try{
            int i = 1/0;
            System.out.println(message.getBody());
            channel.basicNack(message.getMessageProperties().getDeliveryTag(),true,false);
        }catch (Exception e){
            System.out.println("手动确认失败");
            channel.basicNack(message.getMessageProperties().getDeliveryTag(),true,false);
        }

    }
}

3、消费端限流
1)yml文件配置

spring:
  rabbitmq:
    host: 10.0.23.83
    username: lifwe
    password: 123456
    virtual-host: amq123
    port: 5672
    listener:
      direct:
        acknowledge-mode: manual #开启限流必须设置为手动确认
        prefetch: 2 #每次拉取的条数,消费完才能再次拉取
      simple:
        acknowledge-mode: manual 
        prefetch: 2

4、TTL 存活时间
1)在配置类中设置整个队列的过期时间

@Bean("mqQueue")
public Queue getQueue(){
    return QueueBuilder.durable(MQ_QUEUE).ttl(5000).build();
}

2)给指定消息设置过期时间

MessageProperties messageProperties = new MessageProperties();
messageProperties.setExpiration("10000"); // 设置过期时间,单位:毫秒
byte[] msgBytes = "测试消息自动过期".getBytes();
Message message = new Message(msgBytes, messageProperties);
rabbitTemplate.convertAndSend("TTL_EXCHANGE", "TTL", message);

当队列过期时间与指定消息过期时间冲突时,以最小的为准

5、死信队列
DLX:Dead Letter Exchange 死信交换机,即当消息dead后从当前队列进入死信交换机
进入死信交换机的三种情况:
1)queue设置了过期时间,当过了指定时间还未消费的消息进入死信队列
2)当消费的消息拒绝签收并不重新返回当前队列的消息进入死信队列
3)当queue设置了最大的记录,当队列消息满了后,再进来的消息直接进入死信队列
在这里插入图片描述
代码示例:

public static final String MQ_ORDER_EXCHANGE = "mq_order_exchange";
public static final String MQ_ORDER_QUEUE = "mq_order_queue";
public static final String MQ_DLX_EXCHANGE = "mq_dlx_exchange";
public static final String MQ_DLX_QUEUE = "mq_dlx_queue";

/**
 * @return
 * @Author lifwe
 * @Description 订单队列
 * @Date 14:13 2021/3/18
 * @Param
 **/
@Bean("mqOrderQueue")
public Queue getOrderQueue() {
    return QueueBuilder.durable(MQ_ORDER_QUEUE).ttl(10000).deadLetterExchange(MQ_DLX_EXCHANGE).deadLetterRoutingKey("order.dlx").build();
}

/**
 * @return org.springframework.amqp.core.Exchange
 * @Author lifwe
 * @Description 订单交换机
 * @Date 14:17 2021/3/18
 * @Param []
 **/
@Bean("mqOrderExchange")
public Exchange getOrderExchange() {
    return ExchangeBuilder.topicExchange(MQ_ORDER_EXCHANGE).durable(true).build();
}

/**
 * @return org.springframework.amqp.core.Binding
 * @Author lifwe
 * @Description 绑定订单交换机和队列
 * @Date 14:20 2021/3/18
 * @Param [mqOrderQueue, mqOrderExchange]
 **/
@Bean
public Binding getOrderBinding(@Qualifier("mqOrderQueue") Queue mqOrderQueue, @Qualifier("mqOrderExchange") Exchange mqOrderExchange) {
    return BindingBuilder.bind(mqOrderQueue).to(mqOrderExchange).with("order.info.#").noargs();
}

/**
 * @Author lifwe
 * @Description 死信队列
 * @Date 14:22 2021/3/18
 * @Param []
 * @return org.springframework.amqp.core.Queue
 **/
@Bean("mqDtlQueue")
public Queue getDtlQueue() {
    return QueueBuilder.durable(MQ_DLX_QUEUE).build();
}

/**
 * @return org.springframework.amqp.core.Exchange
 * @Author lifwe
 * @Description 死信队列交换机
 * @Date 14:17 2021/3/18
 * @Param []
 **/
@Bean("mqDtlExchange")
public Exchange getDtlExchange() {
    return ExchangeBuilder.topicExchange(MQ_DLX_EXCHANGE).durable(true).build();
}

/**
 * @Author lifwe
 * @Description 死信队列交换机绑定
 * @Date 14:24 2021/3/18
 * @Param [mqDtlQueue, mqDtlExchange]
 * @return org.springframework.amqp.core.Binding
 **/
@Bean
public Binding getDTLBinding(@Qualifier("mqDtlQueue") Queue mqDtlQueue, @Qualifier("mqDtlExchange") Exchange mqDtlExchange) {
    return BindingBuilder.bind(mqDtlQueue).to(mqDtlExchange).with("order.dlx.#").noargs();
}

测试代码:
/**
 * @Author lifwe
 * @Description 测试死信队列
 * @Date 14:26 2021/3/18
 * @Param []
 * @return void
 **/
@org.junit.Test
public void test3(){
    for(int i=0; i<10 ; i++){
        rabbitTemplate.convertAndSend("mq_order_exchange", "order.info."+i, "order.info"+i);
    }
}

order队列设置了10秒的存活时间,当过了10秒后,进入死信队列,示例图:

6、延迟队列
延迟队列即是TTL+死信队列实现,即消费者消费的是死信队列,基于上面的例子进行测试

/**
 * @Author lifwe
 * @Description 延时队列消费
 * @Date 15:00 2021/3/18
 * @Param [message, channel]
 * @return void
 **/
@RabbitListener(queues="mq_dlx_queue")
public void getDlxMqMessage(Message message, Channel channel) throws IOException {
    try{
        System.out.println(new String(message.getBody()));
        channel.basicNack(message.getMessageProperties().getDeliveryTag(),true,false);
    }catch (Exception e){
        System.out.println("手动确认失败");
        channel.basicNack(message.getMessageProperties().getDeliveryTag(),true,false);
    }

}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值