本文基于
RocketMQ 4.x + rocketmq-spring-boot-starter 2.3.1
,从零搭建,逐步讲解 RocketMQ 11大核心特性,每一段代码都能直接跑。
在 pom.xml
文件添加:
<dependency>
<groupId>org.apache.rocketmqgroupId>
<artifactId>rocketmq-spring-boot-starterartifactId>
<version>2.3.1version>
dependency>
application.yml
server:
port: 8080
spring:
rocketmq:
name-server: 127.0.0.1:9876 # RocketMQ NameServer 地址
producer:
group: demo-producer-group # 默认生产者组
consumer:
group: demo-consumer-group # 默认消费者组
本地启动 RocketMQ 可以使用 Docker,示例见文末。
package com.example.rocketmq.producer;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
@Service
public class StandardMessageProducer {
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* 发送普通消息
* @param topic 消息主题
* @param message 消息内容
*/
public void send(String topic, String message) {
rocketMQTemplate.send(topic, MessageBuilder.withPayload(message).build());
}
}
package com.example.rocketmq.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
* 普通消息消费者
*/
@Service
@RocketMQMessageListener(topic = "register-topic", consumerGroup = "register-consumer-group")
public class StandardMessageConsumer implements RocketMQListener<String> {
@Override
public void onMessage(String message) {
System.out.println("【普通消息】收到消息:" + message);
}
}
package com.example.rocketmq.controller;
import com.example.rocketmq.producer.StandardMessageProducer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/standard")
public class StandardMessageController {
@Autowired
private StandardMessageProducer producer;
@PostMapping("/send")
public String sendMessage(@RequestParam String message) {
producer.send("register-topic", message);
return "普通消息发送成功";
}
}
package com.example.rocketmq.producer;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
@Service
public class DelayedMessageProducer {
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* 发送延时消息
* @param topic 消息主题
* @param message 消息内容
* @param delayLevel 延迟等级
*/
public void send(String topic, String message, int delayLevel) {
rocketMQTemplate.syncSend(topic, MessageBuilder.withPayload(message).build(), 3000, delayLevel);
}
}
package com.example.rocketmq.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
* 延迟消息消费者
*/
@Service
@RocketMQMessageListener(topic = "order-cancel-topic", consumerGroup = "delay-consumer-group")
public class DelayedMessageConsumer implements RocketMQListener<String> {
@Override
public void onMessage(String message) {
System.out.println("【延迟消息】收到消息:" + message);
}
}
package com.example.rocketmq.controller;
import com.example.rocketmq.producer.DelayedMessageProducer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/delay")
public class DelayedMessageController {
@Autowired
private DelayedMessageProducer producer;
@PostMapping("/send")
public String sendDelayMessage(@RequestParam String message, @RequestParam int delayLevel) {
producer.send("order-cancel-topic", message, delayLevel);
return "延迟消息发送成功";
}
}
注意:RocketMQ 支持固定的延迟等级,不支持任意延迟。
package com.example.rocketmq.producer;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class OrderedMessageProducer {
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* 发送顺序消息
* @param topic 消息主题
* @param message 消息内容
* @param hashKey 用于分区的 key
*/
public void send(String topic, String message, String hashKey) {
rocketMQTemplate.syncSendOrderly(topic, message, hashKey);
}
}
package com.example.rocketmq.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
* 顺序消息消费者
*/
@Service
@RocketMQMessageListener(topic = "order-topic", consumerGroup = "order-consumer-group")
public class OrderedMessageConsumer implements RocketMQListener<String> {
@Override
public void onMessage(String message) {
System.out.println("【顺序消息】收到消息:" + message);
}
}
package com.example.rocketmq.controller;
import com.example.rocketmq.producer.OrderedMessageProducer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/order")
public class OrderedMessageController {
@Autowired
private OrderedMessageProducer producer;
@PostMapping("/send")
public String sendOrderedMessage(@RequestParam String message, @RequestParam String hashKey) {
producer.send("order-topic", message, hashKey);
return "顺序消息发送成功";
}
}
package com.example.rocketmq.producer;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
@Service
public class TransactionalMessageProducer {
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* 发送事务消息
* @param topic 消息主题
* @param message 消息内容
*/
public void send(String topic, String message) {
Message<String> msg = MessageBuilder.withPayload(message).build();
rocketMQTemplate.sendMessageInTransaction(topic, msg, null);
}
}
package com.example.rocketmq.listener;
import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
/**
* 事务消息监听器
*/
@Component
@RocketMQTransactionListener(txProducerGroup = "demo-producer-group")
public class TransactionListenerImpl implements RocketMQLocalTransactionListener {
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message message, Object o) {
// 执行本地事务
System.out.println("执行本地事务:" + message.getPayload());
// 这里模拟成功提交
return RocketMQLocalTransactionState.COMMIT;
}
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message message) {
// 回查本地事务状态
System.out.println("回查事务状态:" + message.getPayload());
return RocketMQLocalTransactionState.COMMIT;
}
}
package com.example.rocketmq.controller;
import com.example.rocketmq.producer.TransactionalMessageProducer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/transaction")
public class TransactionalMessageController {
@Autowired
private TransactionalMessageProducer producer;
@PostMapping("/send")
public String sendTransactionalMessage(@RequestParam String message) {
producer.send("transactional-topic", message);
return "事务消息发送成功";
}
}
在 application.yml
配置发送重试次数:
spring:
rocketmq:
producer:
retry-times-when-send-failed: 5 # 默认3次,这里改为5次
package com.example.rocketmq.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
* 统计系统消费者
*/
@Service
@RocketMQMessageListener(topic = "order-finished-topic", consumerGroup = "analytics-consumer-group")
public class AnalyticsConsumer implements RocketMQListener<String> {
@Override
public void onMessage(String message) {
System.out.println("【统计系统】收到订单完成消息:" + message);
}
}
package com.example.rocketmq.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
* 风控系统消费者
*/
@Service
@RocketMQMessageListener(topic = "order-finished-topic", consumerGroup = "risk-control-consumer-group")
public class RiskControlConsumer implements RocketMQListener<String> {
@Override
public void onMessage(String message) {
System.out.println("【风控系统】收到订单完成消息:" + message);
}
}
生产者发送消息时打 Tag:
rocketMQTemplate.syncSend("filter-topic:vip", "VIP用户下单");
rocketMQTemplate.syncSend("filter-topic:normal", "普通用户下单");
消费者按 Tag 订阅:
package com.example.rocketmq.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
* Tag过滤消费者
*/
@Service
@RocketMQMessageListener(topic = "filter-topic", consumerGroup = "vip-consumer-group", selectorExpression = "vip")
public class TagFilterConsumer implements RocketMQListener<String> {
@Override
public void onMessage(String message) {
System.out.println("【VIP订单】收到消息:" + message);
}
}
注意:Tag 过滤只能是单标签或者
||
组合。
示意:
Queue | Consumer1 | Consumer2 |
---|---|---|
Q0 | ✔️ | |
Q1 | ✔️ | |
Q2 | ✔️ | |
Q3 | ✔️ |
实际代码和上面一样,只需要部署多个实例**,RocketMQ 自动分配。
若想手动控制(进阶用法,适合批量消费)需改用底层 API MessageListenerConcurrently
。
package com.example.rocketmq.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
* 消息重试消费者
*/
@Service
@RocketMQMessageListener(topic = "retry-topic", consumerGroup = "retry-consumer-group")
public class RetryConsumer implements RocketMQListener<String> {
@Override
public void onMessage(String message) {
System.out.println("【重试机制】收到消息:" + message);
if (message.contains("fail")) {
throw new RuntimeException("消费失败,触发重试");
}
}
}
RocketMQ 会根据消费失败次数进行重试,超过最大次数会进入 死信队列 DLQ。
broker.conf
)fileReservedTime=72 # 消息保存时间(小时)
cleanFileForciblyEnable=true # 启用强制清理
清理规则:
fileReservedTime
时间,会被清除。新建 docker-compose.yml
:
version: '3.7'
services:
namesrv:
image: apache/rocketmq:4.9.3
container_name: rmqnamesrv
ports:
- "9876:9876"
environment:
JAVA_OPT_EXT: "-Xms512m -Xmx512m"
command: sh mqnamesrv
broker:
image: apache/rocketmq:4.9.3
container_name: rmqbroker
ports:
- "10911:10911"
- "10909:10909"
environment:
JAVA_OPT_EXT: "-Xms512m -Xmx512m"
NAMESRV_ADDR: namesrv:9876
BROKER_ID: 0
BROKER_NAME: broker-a
BROKER_CLUSTER_NAME: DefaultCluster
volumes:
- ./broker.conf:/opt/rocketmq-4.9.3/conf/broker.conf
command: sh mqbroker -c /opt/rocketmq-4.9.3/conf/broker.conf
depends_on:
- namesrv
新建 broker.conf
:
brokerClusterName=DefaultCluster
brokerName=broker-a
brokerId=0
deleteWhen=04
fileReservedTime=48
brokerRole=ASYNC_MASTER
flushDiskType=ASYNC_FLUSH
listenPort=10911
执行启动:
docker-compose up -d
功能特性 | 项目应用场景 |
---|---|
普通消息 | 用户注册、订单通知、积分发放 |
定时/延时消息 | 超时关单、定时推送 |
顺序消息 | 订单流转、物流更新 |
事务消息 | 下单扣库存一致性控制 |
消息发送重试 | 保证网络异常时消息可靠送达 |
消费者分类 | 多业务系统独立消费 |
消息过滤 | 精准推送特定类型消息 |
消费者负载均衡 | 消费者水平扩展 |
消费进度管理 | 消费状态持久化,防止重复丢失 |
消息重试 | 消费异常自动重试,保护业务处理 |
存储清理机制 | 硬盘保护,防止大数据量堆积导致系统崩溃 |