Spring Boot Rabbitmq 實現消費者併發監聽

首先,配置一個spring 線程池

@Slf4j
@Configuration
public class TaskExecutorConfig implements AsyncConfigurer {
   @Override
   public Executor getAsyncExecutor() {
      ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
      taskExecutor.setCorePoolSize(4);
      taskExecutor.setMaxPoolSize(8);
      taskExecutor.setQueueCapacity(100);
      taskExecutor.setThreadNamePrefix("myExecutor-");
      taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
      taskExecutor.initialize();
      log.debug("Thread pool initialization.");
      return taskExecutor;
   }

   @Override
   public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
      return null;
   }
}

注意啓動線程池@EnableAsync  在*Application.java上加入這個註解

配置文件: application.yaml

spring:
  rabbitmq:
    host: 192.168.*.*  //ip
    port: 5672 //端口
    username: admin  //用戶名
    password: 123456   //密碼
    publisher-confirms: true  //消息接收確認
    publisher-returns: true  //消息失敗返回
    template:
      mandatory: true  //失敗返回需要爲true
    listener:
      direct:
        acknowledge-mode: manual  //手動 ack
      simple:
        acknowledge-mode: manual  //手動 ack

消息轉化器配置: Jackson2JsonMessageConverter,比默認的SerializerMessageConverter強大

@Configuration
public class RabbitMQConfig {
   @Bean
   public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
      RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
      // 必須設置爲 true,不然當 發送到交換器成功,但是沒有匹配的隊列,不會觸發 ReturnCallback 回調
      // 而且 ReturnCallback 比 ConfirmCallback 先回調,意思就是 ReturnCallback 執行完了纔會執行 ConfirmCallback
      rabbitTemplate.setMandatory(true);
      rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
      return rabbitTemplate;
   }

   @Bean
   public RabbitListenerContainerFactory<?> rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
      SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
      factory.setConnectionFactory(connectionFactory);
      factory.setMessageConverter(new Jackson2JsonMessageConverter());
      factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);    // 修改了messageConverter後需要重新設置手動確認
      return factory;
   }
}

然後,作爲消費者的方法上加入註解監聽異步註解

@Async  // 異步註解, 相當於多個消費者在監聽一個生產者的消息
@RabbitListener(bindings = {  // 消費者監聽, bindings 綁定交換機和隊列
      @QueueBinding(
            exchange = @Exchange(value = "交換機名字", type = ExchangeTypes.TOPIC),  // topic 類型,模糊路由鍵接收
            value = @Queue(value = "隊列名字", durable = "true"), // durable = true 持久化
            key = "路由鍵(例: consumer.#)" // 接收consumer.a、consumer.b 等前綴相同的路由鍵
      )
})
// args 接收的參數,對應生產者傳遞的類型,  channel 接口可用來發送消息或確認消息被消費, @Header 獲取頭信息, tag表示該消息index
public void receiveMsg(Object args, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) {
   //處理args消息信息過程
   
   // 下面是手動消息應答
   // channel.basicAck(tag, false);  作用:消息確認接收,參數2是否批量,true表示一次性ack所有小於tag的消息
   // channel.basicNack(tag, false, true) 作用:拒絕或重新入隊列, 參數2是否批量同上,參數3被拒絕的是否重新入隊列 
   // channel.basicReject(tag, false) 作用:拒絕或重新入隊列(只能一次拒絕一條消息),參數2被拒絕的是否重新入隊列 
}

有一些心得分享一下:有時候只想在一個項目中,監聽一個消費者,比如:消費者1,消費者2都是將接收的消息保存到各自的數據庫中,那麼我們可以在配置文件中指明各自消費者的配置項

spring:
  profiles:
    active: 消費者1配置文件

消費者1配置文件
spring:
  rabbitmq:
    routingkey: **.**
    receive-queue: 接收隊列名1

@RabbitListener(bindings = {
      @QueueBinding(
            exchange = @Exchange(value = "交換機名字"),
            value = @Queue(value = "${spring.rabbitmq.receive-queue}", durable = "true"),
            key = "${spring.rabbitmq.routingkey}"
      )
})

這樣在註解中使用spel 表達式,就可以獲取對應的值,動態監聽消費者

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章