rabbitmq整合springboot

50 阅读2分钟

本章内容

  1. rabbitmq如何整合springboot?
  2. 插件延迟方案

springboot整合rabbitmq

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-amqp</artifactId>
 </dependency>
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-test</artifactId>
     <scope>test</scope>
 </dependency>
 <dependency>
     <groupId>org.springframework.amqp</groupId>
     <artifactId>spring-rabbit-test</artifactId>
     <scope>test</scope>
 </dependency>
 server:
   port: 8080
 spring:
   rabbitmq:
     host: 127.0.0.1
     port: 5672
     password: 123456
     username: zhazha
     virtual-host: / # 虚拟主机

virtual-host本质是根据用户账户分隔出不同的虚拟机, 这样实现各个虚拟机数据的隔离, 但是这种虚拟主机可能共用同一个物理组件, 比如虚拟主机A和虚拟主机B可能共享相同的物理主机上的exchangequeue, 但是在共享的基础上却能做到数据分隔, 这是virtual-host的热点特性

通过延迟插件实现延迟队列

大体步骤

  1. 下载插件
  2. 复制到rabbitmq插件目录
  3. 执行命令
  4. 使用

下载插件

先去rabbitmq github 官方地址: github.com/rabbitmq/ra…

去下载合适的插件

我下载的是这个版本: github.com/rabbitmq/ra…

复制到rabbitmq

找到rabbitmq的plugins文件夹

将插件复制进去

执行命令

 rabbitmq-plugins.bat enable rabbitmq_delayed_message_exchange

使用下面命令可以查看rabbitmq开启了几个插件

 rabbitmq_server-3.11.13\sbin>rabbitmq-plugins.bat list | findstr delay
 [E ] rabbitmq_delayed_message_exchange 3.11.1

怎么用?

核心在于:

 public static final String DELAY_EXCHANGE_TYPE = "x-delayed-message";
 public static final String DELAY_DELAY_TYPE = "x-delayed-type";
 ​
 @Bean
 public CustomExchange dlxExchange() {
     HashMap<String, Object> arguments = new HashMap<>();
     arguments.put(DELAY_DELAY_TYPE, "direct");
     return new CustomExchange(DELAY_EXCHANGE, DELAY_EXCHANGE_TYPE, 
                               true, true, arguments);
 }

"x-delayed-message"和"x-delayed-type"

其它代码都一样除了 Binding Bean 代码:

 @Bean
 public Binding dlxBinding() {
    return BindingBuilder.bind(dlxQueue()).to(dlxExchange()).with("").noargs();
 }

消费者完整代码:

 @Configuration
 public class RabbitConsumerConfig {
     
     public static final String DELAY_QUEUE = "delay_queue";
     public static final String DELAY_EXCHANGE = "delay_exchange";
     public static final String DELAY_EXCHANGE_TYPE = "x-delayed-message";
     public static final String DELAY_DELAY_TYPE = "x-delayed-type";
     
     @Bean
     public CustomExchange dlxExchange() {
         HashMap<String, Object> arguments = new HashMap<>();
         arguments.put(DELAY_DELAY_TYPE, "direct");
         return new CustomExchange(DELAY_EXCHANGE, DELAY_EXCHANGE_TYPE,
                 true, true, arguments);
     }
     
     @Bean
     public Queue dlxQueue() {
         return QueueBuilder.durable(DELAY_QUEUE)
                 .autoDelete()
                 .build();
     }
     
     @Bean
     public Binding dlxBinding() {
         return BindingBuilder.bind(dlxQueue()).to(dlxExchange()).with("").noargs();
     }
     
 }
 @Slf4j
 @Component
 public class ConsumerListener {
    
    @RabbitListener(queues = {RabbitConsumerConfig.DELAY_QUEUE})
    public void messageHandler(Message message, Channel channel) throws IOException {
       System.err.println("message: " + new String(message.getBody(), Charset.defaultCharset()));
       log.info("收到消息的时间: " + DatePattern.NORM_DATETIME_FORMAT.format(new Date()));
       channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }
    
 }

问: 那延迟时间怎么定义?

答: 消费者自定义延迟时间, 因为此时在 queue 上定义 消息过期时间 失效

消息队列TTL的失效

image.png

image.png

image.png

image.png

随后记录到的时间:

 发送消息时间 2023-04-22 09:03:55
 收到消息的时间: 2023-04-22 09:03:55 内容: hehe

说明延迟队列对消息的过期时间配置失效

那没办法只能在消费者定义过期时间了

image.png

生产者TTL配置

 @GetMapping("send/{message}")
 public String sendMsg(@PathVariable(name = "message") String message) {
     rabbitTemplate.convertAndSend(DELAY_EXCHANGE, "", message,
             msg1 -> {
                 msg1.getMessageProperties().setDelay(3000);
                 return msg1;
             });
     return "success";
 }

消费者完成代码:

 @Slf4j
 public class MyMessagePostProcessor implements MessagePostProcessor {
    
    private final String headerName;
    private final String headerValue;
    private final Integer delayTime;
    
    public MyMessagePostProcessor(String headerName, String headerValue, Integer delayTime) {
       this.headerName = headerName;
       this.headerValue = headerValue;
       this.delayTime = delayTime;
    }
    
    @Override
    public Message postProcessMessage(Message message) throws AmqpException {
       MessageProperties messageProperties = message.getMessageProperties();
       messageProperties.setHeader(headerName, headerValue);
       MessageProperties properties = message.getMessageProperties();
       properties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
       properties.setContentEncoding("UTF-8");
       if (delayTime != null) {
          properties.setDelay(delayTime);
       }
       log.info("发送消息时间 {}",
             DatePattern.NORM_DATETIME_FORMAT.format(new Date()));
       return message;
    }
    
 }
 @RestController
 @Slf4j
 public class RabbitmqController {
     public static final String DELAY_EXCHANGE = "delay_exchange";
 
     @Resource
     private AmqpTemplate rabbitTemplate;
 
     @GetMapping("sendDelayMsg/{message}/{delayTime}")
     public void sendMessage(@PathVariable("message") String message,
                             @PathVariable(name = "delayTime", required = false) Integer delayTime) {
         rabbitTemplate.convertAndSend(DELAY_EXCHANGE, "", message,
                 new MyMessagePostProcessor("prefix", "suffix", delayTime));
     }
 
     @GetMapping("send/{message}")
     public String sendMsg(@PathVariable(name = "message") String message) {
         rabbitTemplate.convertAndSend(DELAY_EXCHANGE, "", message,
                 msg1 -> {
                     msg1.getMessageProperties().setDelay(3000);
                     return msg1;
                 });
         return "success";
     }
 
 }