商城电商day14 消息队列工具 RabbitMQ

本文介绍了RabbitMQ在电商场景中的应用,重点讲解了消息队列工具RabbitMQ的发送确认和手动消费确认机制,以确保消息的可靠传递。同时,详细阐述了如何通过死信交换机实现延迟消息,以及基于延迟插件的延迟消息处理,如商品搜索上下架和取消订单等业务场景。
摘要由CSDN通过智能技术生成

消息队列

标题三、消息队列工具 RabbitMQ

4.1.2 发送确认

有时,业务处理成功,消息也发了,但是我们并不知道消息是否成功到达了rabbitmq,如果由于网络等原因导致业务成功而消息发送失败,那么发送方将出现不一致的问题,此时可以使用rabbitmq的发送确认功能,即要求rabbitmq显式告知我们消息是否已成功发送。

4.1.3 手动消费确认

有时,消息被正确投递到消费方,但是消费方处理失败,那么便会出现消费方的不一致问题。比如:订单已创建的消息发送到用户积分子系统中用于增加用户积分,但是积分消费方处理却都失败了,用户就会问:我购买了东西为什么积分并没有增加呢?

要解决这个问题,需要引入消费方确认,即只有消息被成功处理之后才告知rabbitmq以ack,否则告知rabbitmq以nack

4.2.4 封装发送消息确认

步骤
1 MQProducerAckConfig 实现两个接口 RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnCallback
2 public void init() 初始化两个 一个是消息是否正确到达 Exchange 另一个是消息没有正确到达队列时触发回调

package com.atguigu.gmall.common.config;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * 封装发送端消息确认
 */
@Component
public class MQProducerAckConfig implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnCallback {
   


    //  发送消息: RabbitTemplate
    @Autowired
    private RabbitTemplate rabbitTemplate;



    //  写一个方法
    //  修饰一个非静态的void()方法,在服务器加载Servlet的时候运行,
    //  并且只会被服务器执行一次在构造函数之后执行,init()方法之前执行。
    @PostConstruct
    public void init(){
   
//        只确认消息是否正确到达 Exchange 中
        rabbitTemplate.setConfirmCallback(this);
//        消息没有正确到达队列时触发回调,如果正确到达队列不执行
        rabbitTemplate.setReturnCallback(this);
    }

    /**
     *  <p>
     *   1. 如果消息没有到exchange,则confirm回调,ack=false
     *   2. 如果消息到达exchange,则confirm回调,ack=true
     *   3. exchange到queue成功,则不回调return
     *   4. exchange到queue失败,则回调return
     *
     *
     */

    /**
     * 消息成功发送到交换机上
     * @param correlationData 数据载体带有Id标识的!
     * @param ack   消息是否发送成功
     * @param cause 消息发送失败的原因
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
   
        if(ack){
   
            //  消息成功发送到了交换机
            System.out.println("消息发送成功!");
        }else {
   
            System.out.println("消息发送异常");
        }
    }

    /**
     * 表示消息如果没有成功发送到队列则会执行当前这个方法!
     * @param message 消息主体
     * @param replyCode 应答码
     * @param replyText 描述
     * @param exchange 消息使用的交换器
     * @param routingKey 消息使用的路由键
     */
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
   
        System.out.println("消息主体: " + new String(message.getBody()));
        System.out.println("应答码: " + replyCode);
        System.out.println("描述:" + replyText);
        System.out.println("消息使用的交换器 exchange : " + exchange);
        System.out.println("消息使用的路由键 routing : " + routingKey);
    }
}

4.2.5 封装消息发送工具类 供调用

package com.atguigu.gmall.common.service;


@Service
public class RabbitService {
   

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     *  发送消息
     * @param exchange 交换机
     * @param routingKey 路由键
     * @param message 消息
     */
    public boolean sendMessage(String exchange, String routingKey, Object message) {
   
 
        rabbitTemplate.convertAndSend(exchange, routingKey, message);
        return true;
    }
   
}

4.2.6 测试 发送消息 确认消息

消息发送端

package com.atguigu.gmall.mq.controller;


@RestController
@RequestMapping("/mq")
@Slf4j
public class MqController {
   


   @Autowired
   private RabbitService rabbitService;


   /**
    * 消息发送
    */
   //http://cart.gmall.com/8282/mq/sendConfirm
   @GetMapping("sendConfirm")
   public Result sendConfirm() {
   
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      rabbitService.sendMessage("exchange.confirm", "routing.confirm", sdf.format(new Date()));
      return Result.ok();
   }
}

消息接收端

package com.atguigu.gmall.mq.receiver;


@Component
@Configuration
public class ConfirmReceiver {
   

@SneakyThrows
@RabbitListener(bindings=@QueueBinding(
        value = @Queue(value = "queue.confirm",autoDelete = "false"),
        exchange = @Exchange(value = "exchange.confirm",autoDelete = "true"),
        key = {
   "routing.confirm"}))
public void process(Message message, Channel channel){
   
    System.out.println("RabbitListener:"+new String(message.getBody()));

    // 采用手动应答模式, 手动确认应答更为安全稳定
    //如果手动确定了,再出异常,mq不会通知;如果没有手动确认,抛异常mq会一直通知
    //channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        // false 确认一个消息,true 批量确认
     channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    
}
}

4.3改造商品搜索上下架

4.3.1 定义商品上下架常量

在rabbit-util模块中导入常量类MqConst。

/**
 * 商品上下架
 */
public static final String EXCHANGE_DIRECT_GOODS = "exchange.direct.goods";
public static final String ROUTING_GOODS_UPPER = "goods.upper";
public static final String ROUTING_GOODS_LOWER = "goods.lower";
//队列
public static final String QUEUE_GOODS_UPPER  = "queue.goods.upper";
public static final String QUEUE_GOODS_LOWER  = "queue.goods.lower";

4.3.3 service-product发送消息

我在商品上架与商品添加时发送消息 就是更新Good 不止更新skuInfoUp.setIsSale(1);
商品上架

原来的

    
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明月常新

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值