RabbitMQ 学习笔记之订阅模型-生产者重试-消费者重新消费-Java代码层面。

添加maven依赖


    org.springframework.boot
    spring-boot-starter-amqp


            org.apache.rocketmq
            rocketmq-client
            4.4.0
        

    org.springframework.amqp
    spring-rabbit-test
    test

配置

spring.rabbitmq.host=
spring.rabbitmq.port=
spring.rabbitmq.password=
spring.rabbitmq.username=
#默认为/
spring.rabbitmq.virtual-host=/
#这里根据版本的不同 具体设置方法不一样
#高版本使用这个 意思就是生产者异步进行消息发送成功的确认
spring.rabbitmq.publisher-confirm-type=correlated
spring.rabbitmq.publisher-returns=true

#消费者开启手动的消息确认
#开启订阅模型-直连消息的手动确认
spring.rabbitmq.listener.direct.acknowledge-mode=manual
#spring.rabbitmq.listener.simple.acknowledge-mode=manual

生产者

消息重试机制:

1.发送时使用redis,将msgID记录到redis里面
2.发送失败,从redis里根据消息id拿到message信息
3.发送成功,从redis里删除消息id和message
package cn.gwm.sales.inter.order.service.data.impl;

import cn.gwm.sales.inter.order.service.data.RabbitMQService;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.UUID;
import java.util.concurrent.TimeUnit;


@Service
@Slf4j(topic = "rabbitMQ-G-TMS")
public class RabbitMQServiceImpl {

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private RedisTemplate  redisTemplate;

    public void sendData(Object data){
        //开始发送
        String jsonStrng = JSONObject.toJSONString(data);
        log.info("Send message data:{}", jsonStrng);
        //设置message与messageId
        String msgId = UUID.randomUUID().toString();
        Message message = MessageBuilder.withBody(jsonStrng.getBytes()).setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN).setCorrelationId(msgId).build();
        CorrelationData correlationData = new CorrelationData();
        correlationData.setId(msgId);

        rabbitTemplate.convertAndSend("交换机名字", "key名字", message,correlationData);
        //broker失败处理
        rabbitTemplate.setConfirmCallback(confirmCallback);
        //将msgId放到redis里,方便发送失败的时候,重新发送
        redisTemplate.opsForValue().set(msgId,jsonStrng);
        //queue失败处理
//        rabbitTemplate.setReturnCallback(returnCallback);
    }

    //消息成功到交换机 或者 没有成功到交换机
    private RabbitTemplate.ConfirmCallback confirmCallback = (correlationData, ack, cause) -> {
//        String messageId = correlationData.getId();
        if (!ack) {
            log.info("消费发送失败,correlationData:{}",correlationData.getId());
            log.info("消息内容:{}",redisTemplate.opsForValue().get(correlationData.getId()));
        }else{
            log.info("redis删除MsgId,id:{}",correlationData.getId());
            redisTemplate.expire(correlationData.getId(),60, TimeUnit.SECONDS);
        }
    };

    //消息没有加入到队列中 会调用此方法
    private RabbitTemplate.ReturnCallback returnCallback = (message, replyCode, replyText, exchange, routingKey) -> log.info("returnCallback:message:{}replyCode:{}replyText:{}exchange:{}routingKey:{}", message, replyCode, replyText, exchange, routingKey);


}

消费者

手动开启确认与自动消息确认的区别:

1.自动确认
使用自动确认的时候,消费成功,会自动告诉broker,消费失败时,比如程序异常,会将消息放回队列,会造成不断的消费这条消息,程序会卡死。比如发送消费成功之后,程序异常了,会造成消息假消费成功。
2.手动确认
自己去确认,什么时候算成功,什么时候算失败。

开启手动开启:

#开始手动确认
spring.rabbitmq.listener.direct.acknowledge-mode=manual
#spring.rabbitmq.listener.direct.acknowledge-mode=manual
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Slf4j(topic = "consumer-mq")
public class MyConsumer {

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = ""),
            exchange = @Exchange(name = ""),
            key = ""
    ))
    @RabbitHandler
    public void test(Message message, Channel channel){
        try{
            System.out.println("consumer--:"+message.getMessageProperties()+":"+new String(message.getBody()));
            //确认消息,取消送回队列
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }catch(Exception e){
            //程序异常
            e.printStackTrace();//TODO 业务处理
            //拒绝这条消息,取消放回队列,丢弃这条数据
//            channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
            //重新消费这条消息
//            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,false);
        }

    }
}

 

你可能感兴趣的:(RabbitMQ 学习笔记之订阅模型-生产者重试-消费者重新消费-Java代码层面。)