SpringBoot 中集成RocketMQ

 

SpringBoot 中集成RocketMQ

 

1、依赖与Springboot版本

 <properties>
        <java.version>17</java.version>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <rocketmq.version>5.3.0</rocketmq.version>
        <jaeger.version>1.6.0</jaeger.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>3.0.4</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.apache.rocketmq</groupId>
                <artifactId>rocketmq-all</artifactId>
                <version>${rocketmq.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.rocketmq</groupId>
                <artifactId>rocketmq-client</artifactId>
                <version>${rocketmq.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.rocketmq</groupId>
                <artifactId>rocketmq-tools</artifactId>
                <version>${rocketmq.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.rocketmq</groupId>
                <artifactId>rocketmq-acl</artifactId>
                <version>${rocketmq.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

 <dependencies>
        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-spring-boot-starter</artifactId>
            <version>2.3.1</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.rocketmq</groupId>
                    <artifactId>rocketmq-client</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-client</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>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

 

2、配置文件

server:
  port: 9000

spring:
  application:
    name: rocketmq-demo

rocketmq:
  name-server: 192.168.179.128:9876
  producer:
    group: my-test-group
    send-message-timeout: 3000
    retry-times-when-send-failed: 3
    retry-times-when-send-async-failed: 3
  consumer:
#    配置默认的消费者组
    group: my-test-consumer-group

 

3、基础使用介绍

1、普通消息

生产者代码:

@Service
public class SimpleProducer {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public void sendMessage(String message) {
        // 发送普通消息
        rocketMQTemplate.convertAndSend("simple-topic", message);
        System.out.println("发送消息:" + message);
    }

    public void sendMessageWithTag(String message, String tag) {
        // 发送带标签的消息
        rocketMQTemplate.convertAndSend("simple-topic:" + tag, message);
        System.out.println("发送带标签消息:" + message + ", 标签:" + tag);
    }

    public void sendMessageWithKey(String message, String key) {
        // 发送带Key的消息
        Message<String> msg = MessageBuilder.withPayload(message).build();
        msg.getHeaders().put(MessageConst.PROPERTY_KEYS, key);
        rocketMQTemplate.send("simple-topic", msg);
        System.out.println("发送带Key消息:" + message + ", Key:" + key);
    }
}

消费者代码:

@Component
@RocketMQMessageListener(topic = "simple-topic", consumerGroup = "simple-consumer-group")
public class SimpleConsumer implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        System.out.println("接收消息:" + message);
        // 处理消息逻辑, 如果业务抛出异常不会自动提交ACK
    }
}

 

2、同步发送、异步发送、单向发送

@Service
public class SyncAsyncProducer {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public void sendSyncMessage(String message) {
        // 同步发送
        SendResult sendResult = rocketMQTemplate.syncSend("sync-topic", message);
        System.out.println("同步发送结果:" + sendResult.getSendStatus());
    }

    public void sendAsyncMessage(String message) {
        // 异步发送
        rocketMQTemplate.asyncSend("async-topic", message, new SendCallback() {
            @Override
            public void onSuccess(SendResult sendResult) {
                System.out.println("异步发送成功:" + sendResult.getSendStatus());
            }

            @Override
            public void onException(Throwable e) {
                System.out.println("异步发送失败:" + e.getMessage());
            }
        });
    }

    public void sendOneWayMessage(String message) {
        // 单向发送(不关心结果)
        rocketMQTemplate.sendOneWay("oneway-topic", message);
        System.out.println("单向发送完成");
    }
}

 

3、顺序消息

生产者:

@Service
public class OrderProducer {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public void sendOrderMessage(String orderId, String message) {
        // 设置消息队列选择器,确保相同订单的消息发送到同一个队列
        SendResult sendResult = rocketMQTemplate.syncSendOrderly(
            "order-topic",
            MessageBuilder.withPayload(message).build(),
            orderId
        );
        System.out.println("发送顺序消息:" + sendResult.getSendStatus());
    }
}

消息消费者:

@Component
@RocketMQMessageListener(
    topic = "order-topic",
    consumerGroup = "order-consumer-group",
    consumeMode = ConsumeMode.ORDERLY
)
public class OrderConsumer implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        System.out.println("接收顺序消息:" + message);
        // 顺序处理消息逻辑
    }
}

 

4、延时消息

@Service
public class DelayProducer {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;


public void sendDelayMessage(String message, int delayLevel) {
        // 方式一
        Message<String> msg = MessageBuilder.withPayload(message).build();
        // 设置延时等级1-18个延迟级别
        msg.getHeaders().put(MessageConst.PROPERTY_DELAY_TIME_LEVEL, String.valueOf(delayLevel));
        // RocketMQ5.0+版本支持自定义任意的延迟时间 MessageConst.PROPERTY_TIMER_DELAY_SEC
        SendResult sendResult = rocketMQTemplate.syncSend("delay-topic", msg);
        System.out.println("发送延时消息:" + sendResult.getSendStatus());

        // 方式二
        rocketMQTemplate.syncSend("delay-topic",
                MessageBuilder.withPayload(message).build(),
                // 发送超时时间
                rocketMQTemplate.getProducer().getSendMsgTimeout(),
                delayLevel  // 直接传入延迟级别
        );
    }
}

 

5、批量消息

@Service
public class BatchProducer {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public void sendBatchMessages(List<String> messages) {
        // 将消息列表转换为Message列表
        List<Message<String>> messageList = messages.stream()
                .map(msg -> MessageBuilder.withPayload(msg).build())
                .collect(Collectors.toList());

        // 批量发送
        SendResult sendResult = rocketMQTemplate.syncSend("batch-topic", messageList);
        System.out.println("批量发送结果:" + sendResult.getSendStatus());
    }

    public void sendBatchMessagesWithSplitter(List<String> messages) {
        // 使用消息分割器处理大批量消息
        ListSplitter splitter = new ListSplitter(messages, 1000); // 每批最多1000条

        while (splitter.hasNext()) {
            List<String> batch = splitter.next();
            List<Message<String>> messageList = batch.stream()
                    .map(msg -> MessageBuilder.withPayload(msg).build())
                    .collect(Collectors.toList());

            SendResult sendResult = rocketMQTemplate.syncSend("batch-topic", messageList);
            System.out.println("批量发送结果:" + sendResult.getSendStatus());
        }
    }
}

 

6、事务消息

事务消息确保本地事务和消息发送的原子性。

RocketMQ版本不同,使用上有点区别:@RocketMQTransactionListener 这个注解,有点奇怪。2.0.4版本中,是需要指定txProducerGroup指向一个消息发送者组。但是到了2.1.1版本,只能指定rocketMQTemplateBeanMame属性,也就是说如果你有多个发送者组需要有不同的事务消息逻辑,那就需要定义多个RocketMQTemplate。

2.0.4生产者:

 public void sendOrderMessage(Order order) {
        rocketMQTemplate.sendMessageInTransaction(
           // 指定消息发送者组
            "order-tx-group",
            "ORDER_TOPIC:create",
            MessageBuilder.withPayload(order).build(),
            order
        );
    }
    
    public void sendPaymentMessage(Payment payment) {
        rocketMQTemplate.sendMessageInTransaction(
            "payment-tx-group", 
            "PAYMENT_TOPIC:process",
            MessageBuilder.withPayload(payment).build(),
            payment
        );
    }

 

2.0.4事务监听:

// 订单事务监听器
@RocketMQTransactionListener(txProducerGroup = "order-tx-group")
public class OrderTransactionListenerImpl implements RocketMQLocalTransactionListener {
    
    @Autowired
    private OrderService orderService;
    
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        try {
            Order order = (Order) arg;
            boolean success = orderService.createOrder(order);
            return success ? RocketMQLocalTransactionState.COMMIT : 
                           RocketMQLocalTransactionState.ROLLBACK;
        } catch (Exception e) {
            return RocketMQLocalTransactionState.ROLLBACK;
        }
    }
    
    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        // 检查订单事务状态
        return orderService.checkOrderStatus(msg);
    }
}

// 支付事务监听器
@RocketMQTransactionListener(txProducerGroup = "payment-tx-group")
public class PaymentTransactionListenerImpl implements RocketMQLocalTransactionListener {
    
    @Autowired
    private PaymentService paymentService;
    
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        try {
            Payment payment = (Payment) arg;
            boolean success = paymentService.processPayment(payment);
            return success ? RocketMQLocalTransactionState.COMMIT : 
                           RocketMQLocalTransactionState.ROLLBACK;
        } catch (Exception e) {
            return RocketMQLocalTransactionState.ROLLBACK;
        }
    }
    
    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        // 检查支付事务状态
        return paymentService.checkPaymentStatus(msg);
    }
}

 

2.1.1版本:

@Configuration
public class MultiTemplateConfig {
    
    /**
     * 默认消息模板
     */
    @Bean
    @Primary
    public RocketMQTemplate rocketMQTemplate() {
        return new RocketMQTemplate();
    }
    
    /**
     * 订单业务专用模板
     */
    @Bean("OrderRocketMQTemplate")
    public RocketMQTemplate orderRocketMQTemplate() {
        RocketMQTemplate template = new RocketMQTemplate();
        // 可以配置订单专用的参数
        return template;
    }
    
    /**
     * 支付业务专用模板
     */
    @Bean("PaymentRocketMQTemplate")  
    public RocketMQTemplate paymentRocketMQTemplate() {
        RocketMQTemplate template = new RocketMQTemplate();
        // 可以配置支付专用的参数
        return template;
    }
}

// 订单事务监听器
@RocketMQTransactionListener(rocketMQTemplateBeanName = "OrderRocketMQTemplate")
@Service
public class OrderTransactionListener implements RocketMQLocalTransactionListener {
    // 处理订单相关事务消息
}

// 支付事务监听器  
@RocketMQTransactionListener(rocketMQTemplateBeanName = "PaymentRocketMQTemplate")
@Service
public class PaymentTransactionListener implements RocketMQLocalTransactionListener {
    // 处理支付相关事务消息
}

@Service
public class BusinessService {
    
    @Autowired
    @Qualifier("OrderRocketMQTemplate")
    private RocketMQTemplate orderRocketMQTemplate;
    
    @Autowired
    @Qualifier("PaymentRocketMQTemplate")
    private RocketMQTemplate paymentRocketMQTemplate;
    
    public void processOrder(Order order) {
        // 使用订单专用模板
        orderRocketMQTemplate.sendMessageInTransaction(
            "order-group",
            "ORDER_TOPIC:create",
            MessageBuilder.withPayload(order).build(),
            order
        );
    }
    
    public void processPayment(Payment payment) {
        // 使用支付专用模板
        paymentRocketMQTemplate.sendMessageInTransaction(
            "payment-group", 
            "PAYMENT_TOPIC:process",
            MessageBuilder.withPayload(payment).build(),
            payment
        );
    }
}

 

也可以使用如下的方式扩展RocketmqTemplate

// 订单业务专用模板
@ExtRocketMQTemplateConfiguration(
    value = "orderRocketMQTemplate",
    group = "order-producer-group"
)
public class OrderRocketMQTemplateConfig {
    // 空类即可,注解配置所有参数
}

// 支付业务专用模板  
@ExtRocketMQTemplateConfiguration(
    value = "paymentRocketMQTemplate", 
    group = "payment-producer-group"
)
public class PaymentRocketMQTemplateConfig {
}

 

7、消息过滤

@Service
public class FilterProducer {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public void sendMessageWithUserProperty(String message, String userType) {
        // 发送带用户属性的消息
        Message<String> msg = MessageBuilder.withPayload(message).build();
        msg.getHeaders().put("userType", userType);

        rocketMQTemplate.convertAndSend("filter-topic", msg);
        System.out.println("发送带属性消息:" + message + ", 用户类型:" + userType);
    }

    public void sendMessageWithTag(String message, String tag) {
        // 发送带标签的消息
        rocketMQTemplate.convertAndSend("filter-topic:" + tag, message);
        System.out.println("发送带标签消息:" + message + ", 标签:" + tag);
    }
}

消费者标签过滤:

@Component
@RocketMQMessageListener(
    topic = "filter-topic",
    consumerGroup = "filter-consumer-group",
    selectorExpression = "VIP || SVIP"  // 只消费VIP和SVIP标签的消息
)
public class TagFilterConsumer implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        System.out.println("接收过滤消息:" + message);
    }
}

消费者SQL过滤:

@Component
@RocketMQMessageListener(
    topic = "filter-topic",
    consumerGroup = "sql-filter-consumer-group",
    selectorType = SelectorType.SQL92,
    selectorExpression = "userType = 'VIP' AND age > 18"  // SQL92表达式过滤
)
public class SqlFilterConsumer implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        System.out.println("接收SQL过滤消息:" + message);
    }
}

 

 

4、关于消费失败,消息重试说明
顺序消息机制与普通消息消费失败处理逻辑不一样。

image

普通消息默认最大重试次数16次,时间间隔从10s--2h, 达到最大重试次数后,消息会进入死信对列,人工干预处理。顺序消息会阻塞当前MessageQueue0后面的消息,如果没有指定最大重试次数,会一直重试,如果手动指定了最大的重试次数,达到最大的重试次数后不会进入重试对列与死信对列,需要我们手动处理达到最大次数后的逻辑。比如记录日志,发送告警等。

@Component
@RocketMQMessageListener(
        topic = "order-topic",
        consumerGroup = "order-consumer-group",
        consumeMode = ConsumeMode.ORDERLY,
        maxReconsumeTimes = 5
)
public class OrderConsumer implements RocketMQListener<MessageExt> {


    @Override
    public void onMessage(MessageExt message) {
        // 顺序处理消息逻辑
        try {
            String messageBody = new String(message.getBody(), StandardCharsets.UTF_8);
            System.out.println("接收顺序消息内容:" + messageBody);
            // 处理业务逻辑
            boolean success = false;
            if (!success) {
                // 达到最大重试次数后,返回 SUSPEND_CURRENT_QUEUE_A_MOMENT 会继续重试
                // 需要手动判断重试次数
                if (message.getReconsumeTimes() >= 5) {
                    // 手动处理达到最大重试次数的消息(达到最大重试次数后,记录日志、发送邮件等告警)
                    // 确认消费,避免阻塞
                    return;
                }
               throw new RuntimeException("处理业务逻辑异常");
            }
        } catch (Exception e) {
            System.out.print("顺序消息消费异常");
            throw new RuntimeException("处理业务逻辑异常");
        }
    }
}

 

posted @ 2025-11-23 13:24  邓维-java  阅读(32)  评论(0)    收藏  举报