RocketMQ(九)与Spring Boot的集成(原生方式)

872 阅读2分钟

本文介绍RocketMQ与SpringBoot集成,使用rocketmq-client依赖,使用rocketmq官方原生方式操作mq。而非使用org.apache.rocketmq.spring.core.RocketMQTemplate

RocketMQTemplate只需要配置即可使用,比较简单,原理差不多,可以自行百度~

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <modules>
    <module>springboot-rocketmq-demo-common</module>
    <module>springboot-rocketmq-demo-config</module>
    <module>springboot-rocketmq-demo-web</module>
    <module>start</module>
  </modules>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.7.RELEASE</version>
    <relativePath/>
  </parent>

  <groupId>org.example</groupId>
  <artifactId>springboot-rocketmq-demo</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <properties>
    <project.version>1.0-SNAPSHOT</project.version>
    <lombok.version>1.18.16</lombok.version>
    <junit.version>4.13.1</junit.version>
    <commons-lang3.version>3.12.0</commons-lang3.version>
    <hutool.version>5.7.20</hutool.version>
    <fastjson.version>1.2.79</fastjson.version>
    <rocketmq.version>4.9.1</rocketmq.version>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>${hutool.version}</version>
      </dependency>
      <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>${lombok.version}</version>
        <scope>provided</scope>
      </dependency>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
        <scope>test</scope>
      </dependency>
      <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>${fastjson.version}</version>
      </dependency>
      <dependency>
        <groupId>org.apache.rocketmq</groupId>
        <artifactId>rocketmq-client</artifactId>
        <version>${rocketmq.version}</version>
      </dependency>
      <dependency>
        <groupId>org.example</groupId>
        <artifactId>springboot-rocketmq-demo-common</artifactId>
        <version>${project.version}</version>
      </dependency>
      <dependency>
        <groupId>org.example</groupId>
        <artifactId>springboot-rocketmq-demo-config</artifactId>
        <version>${project.version}</version>
      </dependency>
      <dependency>
        <groupId>org.example</groupId>
        <artifactId>springboot-rocketmq-demo-web</artifactId>
        <version>${project.version}</version>
      </dependency>
    </dependencies>
  </dependencyManagement>

</project>

生产者核心配置类

/**
 * @author yongen
 * @description: 生产者配置
 * @date 2022/2/9 2:18 PM
 */
@Configuration
@Slf4j
public class DefaultProducerConfig {

  @Resource
  private RocketMQProducerProperties producerProperties;

  @Bean
  @Primary
  public DefaultMQProducer defaultProducer() throws MQClientException {
    DefaultMQProducer producer = new DefaultMQProducer(producerProperties.getGroup());
    producer.setNamesrvAddr(producerProperties.getNamesrvAddr());
    producer.setVipChannelEnabled(false);
    producer.setRetryTimesWhenSendAsyncFailed(producerProperties.getRetryTimesWhenSendAsyncFailed());
    producer.setSendMsgTimeout(producerProperties.getSendMsgTimeout());
    producer.start();
    log.info("RocketMQ Producer 初始化成功: {}", JSONUtil.parse(producerProperties));
    return producer;
  }
}

消费者要实现对消息的监听,这里使用的枚举类定义topic和tag还有具体处理类的关系实现监听:

ConsumerBeanEnum

/**
 * @author yongen
 * @description: 维护topicTag和处理类的关系
 * @date 2022/2/9 3:04 PM
 */
public enum ConsumerBeanEnum {

  ADD_USER("T_DEMO_PROJECT:ADD_USER", "addUserHandler"),
  ADD_ORDER("T_DEMO_PROJECT:ADD_ORDER", "addOrderHandler"),
  ;
  /**
   * TOPIC:TAG 名称
   */
  private String topicTag;
  /**
   * Handler bean名称
   */
  private String beanName;

  public String getTopicTag() {
    return topicTag;
  }

  public void setTopicTag(String topicTag) {
    this.topicTag = topicTag;
  }

  public String getBeanName() {
    return beanName;
  }

  public void setBeanName(String beanName) {
    this.beanName = beanName;
  }

  ConsumerBeanEnum(String topicTag, String beanName) {
    this.topicTag = topicTag;
    this.beanName = beanName;
  }

  public static ConsumerBeanEnum getBeanByTopicTag(String topicTag) {
    for (ConsumerBeanEnum beanEnum : ConsumerBeanEnum.values()) {
      if (beanEnum.getTopicTag().equals(topicTag)) {
        return beanEnum;
      }
    }
    return null;
  }
}

AbstractConsumerListener

/**
 * @author yongen
 * @description: 抽象消费消息监听类
 * @date 2022/2/9 2:52 PM
 */
@Configuration
@Slf4j
public abstract class AbstractConsumerListener {

  @Resource
  private RocketMQConsumerProperties rocketMQConsumerProperties;

  /**
   * 开启消费注册
   *
   * @param topic
   * @param tags  支持多个tag, 如 tag1 || tag2 || tag3
   * @throws MQClientException
   */
  public void listener(String topic, String tags) throws MQClientException {
    log.info("开启【{}】:【{}】 消费者....", topic, tags);
    DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(rocketMQConsumerProperties.getGroup());
    consumer.setNamesrvAddr(rocketMQConsumerProperties.getNamesrvAddr());
    consumer.subscribe(topic, tags);
    // 开启内部类实现监听
    consumer.registerMessageListener(new MessageListenerConcurrently() {
      @Override
      public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        return AbstractConsumerListener.this.onMessage(msgs);
      }
    });
    consumer.start();
  }

  /**
   * 处理body的业务
   *
   * @param msgs
   * @return ConsumeConcurrentlyStatus
   */
  public abstract ConsumeConcurrentlyStatus onMessage(List<MessageExt> msgs);

DefaultConsumerListener

/**
 * @author yongen
 * @description: 消费消息监听者实现类
 * @date 2022/2/9 2:56 PM
 */
@Configuration
@Slf4j
public class DefaultConsumerListener extends AbstractConsumerListener implements ApplicationContextAware,
    ApplicationListener<ContextRefreshedEvent> {

  /**
   * 上下文
   */
  private ApplicationContext applicationContext;

  @Override
  public ConsumeConcurrentlyStatus onMessage(List<MessageExt> msgs) {
    for (MessageExt msg : msgs) {
      String topicTag = msg.getTopic() + ":" + msg.getTags();
      ConsumerBeanEnum mqConsumerBeanEnum = ConsumerBeanEnum.getBeanByTopicTag(topicTag);
      if (mqConsumerBeanEnum == null) {
        break;
      }
      ConsumeConcurrentlyStatus consumerStatus = null;
      Object serviceBean = applicationContext.getBean(mqConsumerBeanEnum.getBeanName());
      if (null == serviceBean) {
        break;
      }
      if (serviceBean instanceof RocketMQConsumerService) {
        String message = new String(msg.getBody(), StandardCharsets.UTF_8);
        RocketMQConsumerService consumerService = (RocketMQConsumerService) serviceBean;
        // 预处理
        consumerService.beforeHandler(message);
        // 处理
        consumerStatus = consumerService.handle(message);
        // 处理之后
        consumerService.afterHandler(message, LocalDateTime.now(), consumerStatus);
      }
    }
    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
  }

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = applicationContext;
  }

  @Override
  public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
    try {
      // 订阅同一个topic下的多个tag
      super.listener("T_DEMO_PROJECT", "ADD_USER || ADD_ORDER");
    } catch (MQClientException e) {
      log.error("consumer error");
    }
  }
}

完整代码地址:gitee.com/islibin/spr…

核心配置代码在config子模块下。

参考原文:liuyanzhao.com/13065733501…