<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          淘寶七天自動確認收貨,讓你設計,可以怎么實現(xiàn)?(附源碼)

          共 5507字,需瀏覽 12分鐘

           ·

          2021-10-17 23:55

          點擊上方[全棧開發(fā)者社區(qū)]右上角[...][設為星標?

          點擊領取全棧資料全棧資料

          目前常見的應用軟件都有消息的延遲推送的影子,應用也極為廣泛,例如:


          • 淘寶七天自動確認收貨。在我們簽收商品后,物流系統(tǒng)會在七天后延時發(fā)送一個消息給支付系統(tǒng),通知支付系統(tǒng)將款打給商家,這個過程持續(xù)七天,就是使用了消息中間件的延遲推送功能;

          • 12306 購票支付確認頁面。我們在選好票點擊確定跳轉的頁面中往往都會有倒計時,代表著 30 分鐘內訂單不確認的話將會自動取消訂單。其實在下訂單那一刻開始購票業(yè)務系統(tǒng)就會發(fā)送一個延時消息給訂單系統(tǒng),延時 30 分鐘,告訴訂單系統(tǒng)訂單未完成,如果我們在 30 分鐘內完成了訂單,則可以通過邏輯代碼判斷來忽略掉收到的消息。


          在上面兩種場景中,如果我們使用下面兩種傳統(tǒng)解決方案無疑大大降低了系統(tǒng)的整體性能和吞吐量:


          • 使用 Redis?給訂單設置過期時間,最后通過判斷 Redis 中是否還有該訂單來決定訂單是否已經(jīng)完成。這種解決方案相較于消息的延遲推送性能較低,因為我們知道 Redis 都是存儲于內存中,我們遇到惡意下單或者刷單的將會給內存帶來巨大壓力;

          • 使用傳統(tǒng)的數(shù)據(jù)庫輪詢來判斷數(shù)據(jù)庫表中訂單的狀態(tài),這無疑增加了 IO 次數(shù),性能極低;

          • 使用 JVM 原生的 DelayQueue ,也是大量占用內存,而且沒有持久化策略,系統(tǒng)宕機或者重啟都會丟失訂單信息。


          消息延遲推送的實現(xiàn)


          在 RabbitMQ 3.6.x 之前我們一般采用信隊列 + TTL過期時間來實現(xiàn)延遲隊列,我們這里不做過多介紹。


          在 RabbitMQ 3.6.x 開始,RabbitMQ 官方提供了延遲隊列的插件,可以下載放置到 RabbitMQ 根目錄下的 plugins 下。


          插件下載地址:https://github.com/rabbitmq/rabbitmq-delayed-message-exchange



          首先,我們創(chuàng)建交換機和消息隊列。


          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;
          @Configurationpublic 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 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) 來開啟延遲隊列,也可以設置為以下內容傳入交換機聲明的方法中,因為第一種方式的底層就是通過這種方式來實現(xiàn)的。


          //Map pros = new HashMap<>();//設置交換機支持延遲消息推送//pros.put("x-delayed-message", "topic");TopicExchange exchange = new TopicExchange(LAZY_EXCHANGE, true, false, pros);

          發(fā)送消息時我們需要指定延遲推送的時間,我們這里在發(fā)送消息的方法中傳入?yún)?shù) 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;
          @Componentpublic 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());
          //發(fā)送消息時指定 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;
          @Componentpublic?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())); }}

          測試結果

          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 秒后收到了消息 “l(fā)azy receive hello spring boot:”。


          轉自:海向,

          接:cnblogs.com/haixiang/p/10966985.html

          覺得本文對你有幫助?請分享給更多人

          關注「全棧開發(fā)者社區(qū)」加星標,提升全棧技能

          本公眾號會不定期給大家發(fā)福利,包括送書、學習資源等,敬請期待吧!

          如果感覺推送內容不錯,不妨右下角點個在看轉發(fā)朋友圈或收藏,感謝支持。


          好文章,留言、點贊、在看和分享一條龍吧??

          瀏覽 75
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  午夜日韩在线 | 97爱爱| 台湾综合在线观看 | 亚洲AV无码成人精品区在线欢看 | 俺去了俺也去超碰在线 |