SpringBoot+RabbitMq配置与使用死信队列

291 阅读1分钟

一、RabbitConfig配置

 //定义多线程消费消息监听器factory
 @Bean("mutiListenerFactory")
    SimpleRabbitListenerContainerFactory mutiListenerFactory() {
        SimpleRabbitListenerContainerFactory containerFactory = new SimpleRabbitListenerContainerFactory();
        factoryConfigurer.configure(containerFactory, connectionFactory);
        containerFactory.setConcurrentConsumers(10);   //最小开启10个线程消费消息
        containerFactory.setMessageConverter(new Jackson2JsonMessageConverter());
        containerFactory.setPrefetchCount(10);
        containerFactory.setMaxConcurrentConsumers(20);
        containerFactory.setTxSize(10);
        return containerFactory;
    }


//1 死信队列
    @Bean
    public Queue deadQueue() {
        HashMap<String, Object> args = new HashMap<>();
        args.put("x-dead-letter-routing-key", environment.getProperty("rabbitMq.deadletter.routingkey"));  //ttl过了后,发往
        args.put("x-dead-letter-exchange", environment.getProperty("rabbitMq.deadletter.exchange"));
        //args.put("x-message-ttl", 5000);   //针对整个队列
        //args.put("x-max-length",10);   //队列长度
        //args.put("x-overflow","reject-publish" );    //溢出直接拒绝
        return new Queue(environment.getProperty("rabbitMq.deadletter.queue"), true, false, false, args);
    }
    //2 死信交换机
    @Bean
    public TopicExchange realDeadExchange() {
        return new TopicExchange(environment.getProperty("rabbitMq.realQueue.exchange"), true, false);
    }
    //3死信rountingkey绑定
    @Bean
    public Binding deadBinding() {
        return BindingBuilder.bind(deadQueue()).to(realDeadExchange()).with(environment.getProperty("rabbitMq.realQueue.routingkey"));
    }


    //3.接收死信的队列
    @Bean
    public Queue recvieDeadMsgQueue() {
        return new Queue("dead.msg.queue",true,false,false);
    }

    //4.接收死信的交换机 与 死队列绑定交换器一致
    @Bean
    public TopicExchange recvieDeadMsgExchange() {
        return new TopicExchange(environment.getProperty("rabbitMq.deadletter.exchange"), true, false);
    }

    //5.接收死信消息
    @Bean
    public Binding recvieDeadMsgBinding() {
        return BindingBuilder.bind(recvieDeadMsgQueue()).to(recvieDeadMsgExchange()).with(environment.getProperty("rabbitMq.deadletter.routingkey"));
    }

二、生产端

//确认机制
private final ConfirmCallback confirmCallback = new ConfirmCallback() {
       @Override
       public void confirm(CorrelationData correlationData, boolean ack, String s) {
           log.info("correlationData: {}",correlationData);
           log.info("ack: {} ",ack);
           if(!ack){
               //做一些补偿机制等
               correlationData.getId();   //获取中奖信息ID 然后再去数据查询来,做其它操作
               log.info("异常处理....");
           }
       }
   };

   //回调机制
   private final ReturnCallback returnCallback = new ReturnCallback() {
       @Override
       public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
           log.info("return exchange: " + exchange + ", routingKey: "
                   + routingKey + ", replyCode: " + replyCode + ", replyText: " + replyText);
                   //操作......
       }
   };

//发送消息
Message message = MessageBuilder.withBody(objectMapper.writeValueAsBytes(gameLotteryInfoEnity)).
               setDeliveryMode(MessageDeliveryMode.PERSISTENT).setContentEncoding("UTF-8").setContentType("application/json")
               .setExpiration("15000").build();   //setExpiration针对本消息
       rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
       rabbitTemplate.setConfirmCallback(confirmCallback);
       rabbitTemplate.setReturnCallback(returnCallback);
       CorrelationData correlationData = new CorrelationData(gameGiftInfoEnity.getId()+"");
       //exchange, routingKey, object, correlationData
       rabbitTemplate.convertAndSend(environment.getProperty("rabbitMq.realQueue.exchange"), environment.getProperty("rabbitMq.realQueue.routingkey"),  message, correlationData);

三、消费端

 @RabbitListener(queues = "dead.msg.queue",containerFactory = "mutiListenerFactory")
    public void receiverDirectQueue(@Payload Message message, Channel channel, @Headers Map<String,Object> headers) throws IOException {
        log.info("msg1 : {}", message);
        try {
          channel.basicAck((Long)headers.get(AmqpHeaders.DELIVERY_TAG), true);   //确认消息
          gameLotteryInfoMapper.insert(objectMapper.readValue(message.getBody(), GameLotteryInfoEnity.class));
        } catch (IOException e) {
            log.info("处理中奖消息发生异常,重新把消息放入队列");
            channel.basicNack((Long)headers.get(AmqpHeaders.DELIVERY_TAG), true, true);
        }
    }