面试官:淘宝七天自动确定收货,可以怎么实现《福利大放送》

00、福利

近日秋招也要结束了,小码哥祝贺大家都找到心仪的offer,若是没找到合适的也希望你们不畏挫折,努力学习早日找到心仪的offer

这边也给粉丝送出福利——关注留言即可参加!

可以送一本行业相关的技术书籍,但是前提希望大家拿着要看不是吃灰。看得过程中希望能给小马哥一些建议,或者投稿自己的看法。

福利规则

每月20本 每周根据发文数量抽 每篇抽两人 随机抽选(关注+本周文章留言者)

如何参与

小码哥每周发文 给小码哥留言即可参与!若是能分享+点赞那更好了!

重点:参与活动,需关注小码哥,不然不作数,我们将采用随机的形式抽出两个号码(都有机会中奖说不定下个就是你!

01、应用场景

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

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

02、消息延迟推送的实现

在 RabbitMQ 3.6.x 之前我们一般采用死信队列+TTL过期时间来实现延迟队列,我们这里不做过多介绍,可以参考之前文章来了解:TTL、死信队列

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

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

Copyimport 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)来开启延迟队列,也可以设置为以下内容传入交换机声明的方法中,因为第一种方式的底层就是通过这种方式来实现的。

Copy        //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 来设置延迟时间。

Copyimport 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");
Copy/**
 * 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);
 }
}

消费端进行消费

Copyimport 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()));

    }

03、测试结果

Copyimport 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:

觉得不错点个关注和收藏吧这对我们很重要!

04、推荐阅读

腾讯秋招面经汇总-前后端开发篇(带内推链接)

2022腾讯秋招面经导航汇总-测试篇

负载均衡怎么考-两篇通《精选版》

面试常问-Spring Cloud篇

如何做分布式定时任务框架选型

Springboot高频面试题《看完吊打面试官(一)》

Springboot全套注解解析《看不懂算我输》

腾讯三面已上岸

🎈🎈🎈 小码哥公众号:码出宇宙,纯技术干货分享,为圆梦大厂助力。( 最近更新IDEA的全版本激活码,再也不用担心IDEA编不码而烦恼而烦恼)

#小码哥带你圆梦大厂##搞技术你要知道##阿里巴巴面试##面试题目##面经#
全部评论
我每次都是等它自动确认收货,哈哈哈哈
1 回复
分享
发布于 2022-11-07 14:40 北京
好文顶起
1 回复
分享
发布于 2022-11-07 16:24 广东
联易融
校招火热招聘中
官网直投
马哥我的神
1 回复
分享
发布于 2022-11-07 16:35 河北
满满的干货,收藏了
1 回复
分享
发布于 2022-11-07 16:47 安徽
收藏等于学会了
1 回复
分享
发布于 2022-11-07 23:05 广西
正是我需要的!谢谢楼主~
1 回复
分享
发布于 2022-11-07 23:06 广西
感谢大佬分享,给大佬递烟
1 回复
分享
发布于 2022-11-07 23:07 广西
给大佬抠一波666!
1 回复
分享
发布于 2022-11-07 23:08 广西
到我的收藏夹里吃灰吧哈哈哈哈
1 回复
分享
发布于 2022-11-07 23:09 广西
原来自动收货机制是这样的,受教了
点赞 回复
分享
发布于 2022-11-08 02:25 湖北

相关推荐

20 18 评论
分享
牛客网
牛客企业服务