如果淘宝的七天自动确认收货让你设计你用Java怎么实现

 更新时间:2021年09月16日 15:11:25   作者:Java_aoe  
在面试的时候如果面试官问淘宝的七天自动确认收货让你设计,你会怎么具体实现呢?跟着小编看一下下边的实现过程,对大家的学习或工作具有一定的参考借鉴价值

目前常见的应用软件都有消息的延迟推送的影子,应用也极为广泛,例如:

  • 淘宝七天自动确认收货。在我们签收商品后,物流系统会在七天后延时发送一个消息给支付系统,通知支付系统将款打给商家,这个过程持续七天,就是使用了消息中间件的延迟推送功能。
  • 12306 购票支付确认页面。我们在选好票点击确定跳转的页面中往往都会有倒计时,代表着 30 分钟内订单不确认的话将会自动取消订单。其实在下订单那一刻开始购票业务系统就会发送一个延时消息给订单系统,延时30分钟,告诉订单系统订单未完成,如果我们在30分钟内完成了订单,则可以通过逻辑代码判断来忽略掉收到的消息。

在上面两种场景中,如果我们使用下面两种传统解决方案无疑大大降低了系统的整体性能和吞吐量:

  1. 使用 redis 给订单设置过期时间,最后通过判断 redis 中是否还有该订单来决定订单是否已经完成。这种解决方案相较于消息的延迟推送性能较低,因为我们知道 redis 都是存储于内存中,我们遇到恶意下单或者刷单的将会给内存带来巨大压力。
  2. 使用传统的数据库轮询来判断数据库表中订单的状态,这无疑增加了IO次数,性能极低。
  3. 使用 jvm 原生的 DelayQueue ,也是大量占用内存,而且没有持久化策略,系统宕机或者重启都会丢失订单信息。

消息延迟推送的实现

在 RabbitMQ 3.6.x 之前我们一般采用死信队列+TTL过期时间来实现延迟队列,我们这里不做过多介绍。

在 RabbitMQ 3.6.x 开始,RabbitMQ 官方提供了延迟队列的插件,可以下载放置到 RabbitMQ 根目录下的 plugins 下。

面试官问:淘宝七天自动确认收货,让你设计,可以怎么实现?

图片

首先我们创建交换机和消息队列,application.properties 中配置与上一篇文章相同。

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import java.util.HashMap;
import java.util.Map;
 
@Configuration
public class MQConfig {
 
    public static final String LAZY_EXCHANGE = "Ex.LazyExchange";
    public static final String LAZY_QUEUE = "MQ.LazyQueue";
    public static final String LAZY_KEY = "lazy.#";
 
    @Bean
    public TopicExchange lazyExchange(){
        //Map<String, Object> pros = new HashMap<>();
        //设置交换机支持延迟消息推送
        //pros.put("x-delayed-message", "topic");
        TopicExchange exchange = new TopicExchange(LAZY_EXCHANGE, true, false, pros);
        exchange.setDelayed(true);
        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);
    }
}

我们在 Exchange 的声明中可以设置exchange.setDelayed(true)来开启延迟队列,也可以设置为以下内容传入交换机声明的方法中,因为第一种方式的底层就是通过这种方式来实现的。

//Map<String, Object> pros = new HashMap<>();
        //设置交换机支持延迟消息推送
        //pros.put("x-delayed-message", "topic");
        TopicExchange exchange = new TopicExchange(LAZY_EXCHANGE, true, false, pros);

发送消息时我们需要指定延迟推送的时间,我们这里在发送消息的方法中传入参数 new MessagePostProcessor() 是为了获得 Message对象,因为需要借助 Message对象的api 来设置延迟时间。

import com.anqi.mq.config.MQConfig;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessagePostProcessor;
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 java.util.Date;
 
@Component
public class MQSender {
 
    @Autowired
    private RabbitTemplate rabbitTemplate;
 
    //confirmCallback returnCallback 代码省略,请参照上一篇
 
    public void sendLazy(Object message){
        rabbitTemplate.setMandatory(true);
        rabbitTemplate.setConfirmCallback(confirmCallback);
        rabbitTemplate.setReturnCallback(returnCallback);
        //id + 时间戳 全局唯一
        CorrelationData correlationData = new CorrelationData("12345678909"+new Date());
 
        //发送消息时指定 header 延迟时间
        rabbitTemplate.convertAndSend(MQConfig.LAZY_EXCHANGE, "lazy.boot", message,
                new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //设置消息持久化
                message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                //message.getMessageProperties().setHeader("x-delay", "6000");
                message.getMessageProperties().setDelay(6000);
                return message;
            }
        }, correlationData);
    }
}

我们可以观察 setDelay(Integer i)底层代码,也是在 header 中设置 x-delay。等同于我们手动设置 header

message.getMessageProperties().setHeader("x-delay", "6000");
/**
 * Set the x-delay header.
 * @param delay the delay.
 * @since 1.6
 */
public void setDelay(Integer delay) {
    if (delay == null || delay < 0) {
        this.headers.remove(X_DELAY);
    }
    else {
        this.headers.put(X_DELAY, delay);
    }
}

消费端进行消费

import com.rabbitmq.client.Channel;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.stereotype.Component;
 
import java.io.IOException;
import java.util.Map;
 
@Component
public class MQReceiver {
 
    @RabbitListener(queues = "MQ.LazyQueue")
    @RabbitHandler
    public void onLazyMessage(Message msg, Channel channel) throws IOException{
        long deliveryTag = msg.getMessageProperties().getDeliveryTag();
        channel.basicAck(deliveryTag, true);
        System.out.println("lazy receive " + new String(msg.getBody()));
 
    }
    ```
 
## 测试结果[#](https://www.cnblogs.com/haixiang/p/10966985.html#3724420099)
 
```java
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
 
@SpringBootTest
@RunWith(SpringRunner.class)
public class MQSenderTest {
 
    @Autowired
    private MQSender mqSender;
 
    @Test
    public void sendLazy() throws  Exception {
        String msg = "hello spring boot";
 
        mqSender.sendLazy(msg + ":");
    }
}

果然在 6 秒后收到了消息 lazy receive hello spring boot:

到此这篇关于如果淘宝的七天自动确认收货让你设计你用Java怎么实现的文章就介绍到这了,更多相关Java 七天自动确认收货内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 5个并发处理技巧代码示例

    5个并发处理技巧代码示例

    这篇文章主要介绍了5个并发处理技巧代码示例,具有一定参考价值,需要的朋友可以了解下。
    2017-10-10
  • 解决import包时报 Java 程序包不存在的问题

    解决import包时报 Java 程序包不存在的问题

    你是否也有过在import包时idea报错说这个包不存在,可是这个包我们看得到确实存在的情况,不要慌,今天这篇文章带你彻底告别这个问题
    2021-10-10
  • 去掉 IDEA 中 mybatis配置文件的局部背景颜色(图解)

    去掉 IDEA 中 mybatis配置文件的局部背景颜色(图解)

    这篇文章通过图文并茂的形式给大家介绍了去掉IntelliJ IDEA 中 mybatis配置文件的局部背景颜色及mybatis 对应的 xml 文件警告的方法图解,需要的朋友可以参考下
    2018-09-09
  • SpringBoot整合websocket实现即时通信聊天

    SpringBoot整合websocket实现即时通信聊天

    这篇文章主要介绍了SpringBoot整合websocket实现即时通信聊天,实时通信是一个实时通信系统,允许两人或多人使用网络实时的传递文字消息、文件、语音与视频交流,需要的朋友可以参考下
    2022-05-05
  • 使用springCloud+nacos集成seata1.3.0搭建过程

    使用springCloud+nacos集成seata1.3.0搭建过程

    这篇文章主要介绍了使用springCloud+nacos集成seata1.3.0搭建过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-08-08
  • 浅谈MyBatis3 DynamicSql风格语法使用指南

    浅谈MyBatis3 DynamicSql风格语法使用指南

    这篇文章主要介绍了浅谈MyBatis3 DynamicSql风格语法使用指南,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • Java 读取excel 文件流代码实例

    Java 读取excel 文件流代码实例

    这篇文章主要介绍了Java 读取excel 文件流代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • 关于Mybatis实体别名支持通配符扫描问题小结

    关于Mybatis实体别名支持通配符扫描问题小结

    MyBatis可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录,这篇文章主要介绍了Mybatis实体别名支持通配符扫描的问题,需要的朋友可以参考下
    2022-01-01
  • idea生成WebServices接口的完整流程步骤

    idea生成WebServices接口的完整流程步骤

    因为工作需要,数据传输部分需要使用webservice实现,经过两天的研究,实现了一个简单的例子,这篇文章主要给大家介绍了关于idea生成WebServices接口的完整流程步骤,需要的朋友可以参考下
    2024-08-08
  • IDEA2020.3创建web工程的完整步骤

    IDEA2020.3创建web工程的完整步骤

    这篇文章主要给大家介绍了关于IDEA2020.3创建web工程的完整步骤,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01

最新评论