spring boot Rabbitmq整合,延時訊息佇列實現

來源:互聯網
上載者:User

本篇主要記錄Spring boot 整合Rabbitmq,分為兩部分, 第一部分為建立普通訊息佇列, 第二部分為延時訊息佇列實現:

spring boot提供對mq訊息佇列支援amqp相關包,引入即可:

        <!-- rabbit mq -->          <dependency>              <groupId>org.springframework.boot</groupId>              <artifactId>spring-boot-starter-amqp</artifactId>          </dependency>  

屬性設定檔application.properties:

#rabbitmq  spring.rabbitmq.host=127.0.0.1  spring.rabbitmq.port=5672  spring.rabbitmq.username=root  spring.rabbitmq.password=root  

RabbitMq配置類,配置串連工廠以及操作對象:

@Configuration  @ConfigurationProperties(prefix = "spring.rabbitmq")  public class RabbitMQConfiguration {      private static Logger logger = Logger.getLogger(RabbitMQConfiguration.class);      private String host;      private int port;      private String username;      private String password;      // 連結資訊      @Bean      public ConnectionFactory connectionFactory() {          CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host, port);          connectionFactory.setUsername(username);          connectionFactory.setPassword(password);          connectionFactory.setVirtualHost("/");          connectionFactory.setPublisherConfirms(true);          logger.info("Create ConnectionFactory bean ..");          return connectionFactory;      }      @Bean      @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)      public RabbitTemplate rabbitTemplate() {          RabbitTemplate template = new RabbitTemplate(connectionFactory());          return template;      }      //省略getter setter  }  

定義Service介面如下:
暫時不考慮延時隊列,定義發送訊息介面

/**  *   * @author victor  * @desc 訊息佇列服務介面  */  public interface IMessageQueueService {      /**      * 發送訊息到隊列      * @param queue 隊列名稱      * @param message 訊息內容      */      public void send(String queueName,String message);  }  

Service實現

package com.ks.server.service.impl.queue;  import org.springframework.amqp.AmqpException;  import org.springframework.amqp.core.Message;  import org.springframework.amqp.core.MessagePostProcessor;  import org.springframework.amqp.rabbit.core.RabbitTemplate;  import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.stereotype.Service;  import com.base.common.codec.JSONUtils;  import com.ks.common.constant.MQConstant;  import com.ks.common.service.queue.IMessageQueueService;  import com.ks.modal.queue.DLXMessage;  /**  *   * @author victor  * @desc 訊息佇列服務介面實現  */  @Service("messageQueueService")  public class MessageQueueServiceImpl implements IMessageQueueService{      @Autowired      private RabbitTemplate rabbitTemplate;      @Override      public void send(String queueName, String msg) {          rabbitTemplate.convertAndSend(MQConstant.DEFAULT_EXCHANGE,queueName, msg);      }  }  

相關常量類:

package com.ks.common.constant;  /**  *   * @author victor  * @desc Rabbit訊息佇列相關常量  */  public final class MQConstant {      private MQConstant(){      }      //exchange name      public static final String DEFAULT_EXCHANGE = "KSHOP";      //DLX QUEUE      public static final String DEFAULT_DEAD_LETTER_QUEUE_NAME = "kshop.dead.letter.queue";      //DLX repeat QUEUE 死信轉寄隊列      public static final String DEFAULT_REPEAT_TRADE_QUEUE_NAME = "kshop.repeat.trade.queue";      //Hello 測試訊息佇列名稱      public static final String HELLO_QUEUE_NAME = "HELLO";  }  

到現在為止,隊列相關配置,以及使用以及封裝完成,接下來是建立隊列,
這裡我是單獨建立一個配置類,用於隊列配置, 建立Hello隊列樣本如下:

package com.ks.ons.config;  import java.util.HashMap;  import java.util.Map;  import org.springframework.amqp.core.Binding;  import org.springframework.amqp.core.BindingBuilder;  import org.springframework.amqp.core.DirectExchange;  import org.springframework.amqp.core.Queue;  import org.springframework.context.annotation.Bean;  import org.springframework.context.annotation.Configuration;  import com.ks.common.constant.MQConstant;  /**  *   * @author victor  * @desc 隊列配置  */  @Configuration  public class QueueConfiguration {      //通道配置      @Bean      public DirectExchange defaultExchange() {          return new DirectExchange(MQConstant.DEFAULT_EXCHANGE, true, false);      }      /*********************    hello 隊列  測試    *****************/      @Bean      public Queue queue() {          Queue queue = new Queue(MQConstant.HELLO_QUEUE_NAME,true);          return queue;       }      @Bean      public Binding binding() {          return BindingBuilder.bind(queue()).to(defaultExchange()).with(MQConstant.HELLO_QUEUE_NAME);      }  }  

通過配置隊列bean,在程式啟動時會在rabbitmq中建立相關隊列,啟動程式,可以在rabbtmq管理介面看到通道和隊列資訊:

眾所周知,既然有了隊列,用來處理業務的最終還是需要消費者,消費者建立樣本如下:

package com.ks.ons.processor.hello;  import org.springframework.amqp.rabbit.annotation.RabbitHandler;  import org.springframework.amqp.rabbit.annotation.RabbitListener;  import org.springframework.stereotype.Component;  import com.ks.common.constant.MQConstant;  /**  *   * @author victor  * @desc hello 訊息佇列消費者  */  @Component  @RabbitListener(queues = MQConstant.HELLO_QUEUE_NAME)  public class HelloProcessor {      @RabbitHandler      public void process(String content) {          System.out.println("接受訊息:" + content);      }  }  

注入service

@Autowired  private IMessageQueueService messageQueueService;  

發送訊息

messageQueueService.send(MQConstant.HELLO_QUEUE_NAME, "測試發送訊息");  

接下來展示如何?延時隊列,在此之前如果讀者像我一樣對rabbitmq隊列瞭解程度並不深入的話,–> 推薦文章, 可以對rabbitmq延時隊列實現思路有大概瞭解.
在本文中,主要是通過rabbitmq的DLX特性來實現發送延時隊列:
思路如下:

用戶端:指具體往MQ發生訊息端, 用戶端將訊息內容進行自訂封裝, 將訊息中附帶目標隊列名稱。如:用戶端向隊列Q1發送字串“hello” , 延時時間為60秒, 封裝後修改為{“queueName”:”Q1”,”body”: “hello”},此時,將訊息發送到DLX無效信件佇列,而非Q1隊列,並將訊息設定為60秒逾時。

DLX:無效信件佇列,用來儲存有逾時時間資訊的訊息, 並且可以設定當訊息逾時時,轉寄到另一個指定隊列(此處設定轉寄到router), 無消費者,當接收到用戶端訊息之後,等待訊息逾時,將訊息轉寄到指定的Router隊列

Router: 轉寄隊列,用來接收無效信件佇列逾時訊息, 如上樣本訊息,在接收到之後,消費者將訊息解析,擷取queueName,body,再向所擷取的queueName隊列發送一條訊息,內容為body.

Q1,Q2,Q3.: 使用者業務隊列,當Q1收到hello,已經是60秒之後,再進行消費

修改上面代碼 , 新增兩個隊列,
無效信件佇列:存放發送的延時訊息,
路由轉寄隊列:用於接受死信訊息死亡, 並將訊息轉寄到營運目標隊列
修改之後代碼如下:

/**  *   * @author victor  * @desc 隊列配置  */  @Configuration  public class QueueConfiguration {      //通道配置      @Bean      public DirectExchange defaultExchange() {          return new DirectExchange(MQConstant.DEFAULT_EXCHANGE, true, false);      }      @Bean      public Queue repeatTradeQueue() {          Queue queue = new Queue(MQConstant.DEFAULT_REPEAT_TRADE_QUEUE_NAME,true,false,false);          return queue;       }      @Bean      public Binding  drepeatTradeBinding() {          return BindingBuilder.bind(repeatTradeQueue()).to(defaultExchange()).with(MQConstant.DEFAULT_REPEAT_TRADE_QUEUE_NAME);      }      @Bean      public Queue deadLetterQueue() {          Map<String, Object> arguments = new HashMap<>();          arguments.put("x-dead-letter-exchange", MQConstant.DEFAULT_EXCHANGE);          arguments.put("x-dead-letter-routing-key", MQConstant.DEFAULT_REPEAT_TRADE_QUEUE_NAME);          Queue queue = new Queue(MQConstant.DEFAULT_DEAD_LETTER_QUEUE_NAME,true,false,false,arguments);          System.out.println("arguments :" + queue.getArguments());          return queue;       }      @Bean      public Binding  deadLetterBinding() {          return BindingBuilder.bind(deadLetterQueue()).to(defaultExchange()).with(MQConstant.DEFAULT_DEAD_LETTER_QUEUE_NAME);      }      /*********************    hello 隊列  測試    *****************/      @Bean      public Queue queue() {          Queue queue = new Queue(MQConstant.HELLO_QUEUE_NAME,true);          return queue;       }      @Bean      public Binding binding() {          return BindingBuilder.bind(queue()).to(defaultExchange()).with(MQConstant.HELLO_QUEUE_NAME);      }  }  

修改Service服務:

package com.ks.common.service.queue;  /**  *   * @author victor  * @desc 訊息佇列服務介面  */  public interface IMessageQueueService {      /**      * 發送訊息到隊列      * @param queue 隊列名稱      * @param message 訊息內容      */      public void send(String queueName,String message);      /**      * 延遲發送訊息到隊列      * @param queue 隊列名稱      * @param message 訊息內容      * @param times 延遲時間 單位毫秒      */      public void send(String queueName,String message,long times);  }  
package com.ks.server.service.impl.queue;  import org.springframework.amqp.AmqpException;  import org.springframework.amqp.core.Message;  import org.springframework.amqp.core.MessagePostProcessor;  import org.springframework.amqp.rabbit.core.RabbitTemplate;  import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.stereotype.Service;  import com.base.common.codec.JSONUtils;  import com.ks.common.constant.MQConstant;  import com.ks.common.service.queue.IMessageQueueService;  import com.ks.modal.queue.DLXMessage;  /**  *   * @author victor  * @desc 訊息佇列服務介面實現  */  @Service("messageQueueService")  public class MessageQueueServiceImpl implements IMessageQueueService{      @Autowired      private RabbitTemplate rabbitTemplate;      @Override      public void send(String queueName, String msg) {          rabbitTemplate.convertAndSend(MQConstant.DEFAULT_EXCHANGE,queueName, msg);      }      @Override      public void send(String queueName, String msg, long times) {          DLXMessage dlxMessage = new DLXMessage(queueName,msg,times);          MessagePostProcessor processor = new MessagePostProcessor(){              @Override              public Message postProcessMessage(Message message) throws AmqpException {                  message.getMessageProperties().setExpiration(times + "");                  return message;              }          };          dlxMessage.setExchange(MQConstant.DEFAULT_EXCHANGE);          rabbitTemplate.convertAndSend(MQConstant.DEFAULT_EXCHANGE,MQConstant.DEFAULT_DEAD_LETTER_QUEUE_NAME, JSONUtils.toJson(dlxMessage), processor);      }  }  

JSONUtils 為一個JSON工具類

新增訊息實體,用於封裝訊息:

package com.ks.modal.queue;  import java.io.Serializable;  /**  *   * @author victor  * @desc rabbit 死信訊息載體  */  public class DLXMessage implements Serializable {      private static final long serialVersionUID = 9956432152000L;      public DLXMessage() {          super();      }      public DLXMessage(String queueName, String content, long times) {          super();          this.queueName = queueName;          this.content = content;          this.times = times;      }      public DLXMessage(String exchange, String queueName, String content, long times) {          super();          this.exchange = exchange;          this.queueName = queueName;          this.content = content;          this.times = times;      }      private String exchange;      private String queueName;      private String content;      private long times;      //省略getter setter  }  

路由轉寄隊列消費者實現,負責接收逾時訊息,進行轉寄:

package com.ks.ons.processor.system;  import org.springframework.amqp.rabbit.annotation.RabbitHandler;  import org.springframework.amqp.rabbit.annotation.RabbitListener;  import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.stereotype.Component;  import com.base.common.codec.JSONUtils;  import com.ks.common.constant.MQConstant;  import com.ks.common.service.queue.IMessageQueueService;  import com.ks.modal.queue.DLXMessage;  /**  *   * @author victor  * @desc 死信接收處理消費者  */  @Component  @RabbitListener(queues = MQConstant.DEFAULT_REPEAT_TRADE_QUEUE_NAME)  public class TradeProcessor {      @Autowired      private IMessageQueueService messageQueueService;      @RabbitHandler      public void process(String content) {          DLXMessage message = JSONUtils.toBean(content, DLXMessage.class);          messageQueueService.send(message.getQueueName(), message.getContent());      }  }  

啟動項目之後,管理介面如下:

測試程式碼片段:

messageQueueService.send(MQConstant.HELLO_QUEUE_NAME,"測試延遲發送訊息",60000);  

轉自:http://blog.csdn.net/i_vic/article/details/72742277

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.