参考文章:https://blog.csdn.net/gzmyh/article/details/130222388
前置条件、安装好RocketMQ、RocketMQ仪表盘
第一步、引入依赖
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.3</version>
</dependency>
第二步、创建生产者模块
1、配置文件
rocketmq:
# NameServer
name-server: 127.0.0.1:9876
producer:
# 发送消息超时时间,默认3000
send-message-timeout: 30000
# 生产者组
group: groupTest
# 发送消息失败重试次数,默认2
retryTimesWhenSendFailed: 2
# 异步消息重试此处,默认2
retryTimesWhenSendAsyncFailed: 2
2、创建RocketMQTemplate
封装了RocketMQ的生产者API,提供了一系列简单易用的方法,用于发送不同类型的消息, 后面的例子都会用到它
我们要新建一个ExtRocketMQTemplate类去继承RocketMQTemplate
import org.apache.rocketmq.spring.annotation.ExtRocketMQTemplateConfiguration;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
@ExtRocketMQTemplateConfiguration(nameServer = "${rocketmq.name-server}")
public class ExtRocketMQTemplate extends RocketMQTemplate {
}
3 普通消息
普通消息为 Apache RocketMQ 中最基础的消息 , 普通消息一般应用于微服务解耦、事件驱动、数据集成等场景,这些场景大多数要求数据传输通道具有可靠传输的能力,且对消息的处理时机、处理顺序没有特别要求。
3.1 单向消息发送
指发送消息后,不需要等待Broker的响应,直接返回。这种方式适用于不需要关注消息发送结果的场景,如日志记录、统计信息等。
/**
* 发送消息后,不需要等待Broker的响应,直接返回。
* 这种方式适用于不需要关注消息发送结果的场景,如日志记录、统计信息等
* @return
*/
@GetMapping("/sendOneWay")
@ApiOperation(value = "单向发送消息")
@ApiOperationSupport(order = 1)
public void sendOneWay() {
for (int i = 1; i <=3; i++) {
HeroDTO heroDTO = new HeroDTO();
heroDTO.setId(IdUtil.fastUUID());
heroDTO.setName("伽罗"+i);
Message<String> msgs = MessageBuilder.withPayload(JSON.toJSONString(heroDTO))
//设置消息KEYS,一般是数据的唯一ID,主要用于在仪表盘中方便搜索
.setHeader("KEYS", "111")
.build();
//给消息打上射手的标签。主题+tag,中间用“:”分隔,主要是用于消息的过滤,比如说在消费的时候,只消费ess标签下的消息
extRocketMQTemplate.sendOneWay("topicA".concat(":ess"), msgs);
log.info("单向发送消息" + heroDTO);
}
}
3.2 同步发送消息
/**
* syncSend方法会阻塞当前线程,直到消息发送完成并收到了消息服务器的响应。
* 如果消息发送成功,syncSend方法会返回一个SendResult对象,包含了消息的发送状态、消息ID等信息。
* 如果消息发送失败,syncSend方法会抛出一个MessagingException异常。
* @return
*/
@GetMapping("/syncSend")
@ApiOperation(value = "同步发送消息")
@ApiOperationSupport(order = 2)
public void syncSend() {
HeroDTO heroDTO = new HeroDTO();
heroDTO.setId(IdUtil.fastUUID());
heroDTO.setName("鲁班");
Message<String> msgs = MessageBuilder.withPayload(JSON.toJSONString(heroDTO))
//设置消息KEYS,一般是数据的唯一ID,主要用于在仪表盘中方便搜索
.setHeader("KEYS", "222")
.build();
SendResult sendResult = extRocketMQTemplate.syncSend("topicB".concat(":ess"), msgs);
log.info(heroDTO.toString());
log.info(sendResult.toString());
}
3.3 异步发送消息
/**
* asyncSend方法不会阻塞当前线程,而是在另一个线程中异步发送消息。
* 因此,asyncSend方法会立即返回,不会等待消息发送完成。
* 如果需要等待消息发送完成并处理发送结果,可以使用SendCallback回调接口。
* @return
*/
@GetMapping("/asyncSend")
@ApiOperation(value = "异步发送消息")
@ApiOperationSupport(order = 3)
public void asyncSend() {
HeroDTO heroDTO = new HeroDTO();
heroDTO.setId("sunshangxiang");
heroDTO.setName("孙尚香");
Message<String> msgs = MessageBuilder.withPayload(JSON.toJSONString(heroDTO))
//设置消息KEYS,一般是数据的唯一ID,主要用于在仪表盘中方便搜索
.setHeader("KEYS", "333")
.build();
extRocketMQTemplate.asyncSend("topicC".concat(":ess"), msgs, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
log.info(sendResult.toString());
}
@Override
public void onException(Throwable e) {
log.info(e.getMessage());
}
});
}
4 顺序消息
顺序消息是 Apache RocketMQ 提供的一种高级消息类型,支持消费者按照发送消息的先后顺序获取消息,从而实现业务场景中的顺序处理。 相比其他类型消息,顺序消息在发送、存储和投递的处理过程中,更多强调多条消息间的先后顺序关系。
4.1单向顺序消息
/**
* 顺序消息是 Apache RocketMQ 提供的一种高级消息类型,
* 支持消费者按照发送消息的先后顺序获取消息,从而实现业务场景中的顺序处理。
* 相比其他类型消息,顺序消息在发送、存储和投递的处理过程中,更多强调多条消息间的先后顺序关系。
*/
@GetMapping("/sendOneWayOrderly")
@ApiOperation(value = "单向发送顺序消息")
@ApiOperationSupport(order = 4)
public void sendOneWayOrderly() {
for (int i = 1; i <=3; i++) {
HeroDTO heroDTO = new HeroDTO();
heroDTO.setId("zhangfei");
heroDTO.setName("张飞"+i);
Message<String> msgs = MessageBuilder.withPayload(JSON.toJSONString(heroDTO))
//设置消息KEYS,一般是数据的唯一ID,主要用于在仪表盘中方便搜索
.setHeader("KEYS", "444")
.build();
//顺序消息比普通消息多一个参数,第三个参数只要唯一就行,比如ID
extRocketMQTemplate.sendOneWayOrderly("topicD".concat(":tank"), msgs,heroDTO.getId());
}
}
4.2同步发送顺序消息
@GetMapping("/syncSendOrderly")
@ApiOperation(value = "同步发送顺序消息")
@ApiOperationSupport(order = 5)
public void syncSendOrderly() {
for (int i = 1; i <=3; i++) {
HeroDTO heroDTO = new HeroDTO();
heroDTO.setId("guanyu");
heroDTO.setName("关羽"+i);
Message<String> msgs = MessageBuilder.withPayload(JSON.toJSONString(heroDTO))
//设置消息KEYS,一般是数据的唯一ID,主要用于在仪表盘中方便搜索
.setHeader("KEYS", "555")
.build();
SendResult sendResult = extRocketMQTemplate.syncSendOrderly("topicE".concat(":tank"), msgs,heroDTO.getId());
log.info(sendResult.toString());
}
}
4.3异步发送顺序消息
经测试,这里并不能保证消息的顺序
/**
* 异步发送只是多了一个SendCallback参数。注意:异步发送顺序消息并不能严格保证消息的顺序。
*/
@GetMapping("/asyncSendOrderly")
@ApiOperation(value = "异步发送顺序消息")
@ApiOperationSupport(order = 6)
public void asyncSendOrderly() {
for (int i = 1; i <=3; i++) {
HeroDTO heroDTO = new HeroDTO();
heroDTO.setId("xiangyu");
heroDTO.setName("项羽"+i);
Message<String> msgs = MessageBuilder.withPayload(JSON.toJSONString(heroDTO))
//设置消息KEYS,一般是数据的唯一ID,主要用于在仪表盘中方便搜索
.setHeader("KEYS", "666")
.build();
extRocketMQTemplate.asyncSendOrderly("topicF".concat(":tank"), msgs,heroDTO.getId(), new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
log.info(sendResult.toString());
}
@Override
public void onException(Throwable e) {
log.info(e.getMessage());
}
});
}
}
5 延时消息
延时消息是 Apache RocketMQ 提供的一种高级消息类型,消息被发送至服务端后,在指定时间后才能被消费者消费。
@GetMapping("/syncSendDelayTimeSeconds")
@ApiOperation(value = "延时发送消息")
@ApiOperationSupport(order = 7)
public void syncSendDelayTimeSeconds() {
HeroDTO heroDTO = new HeroDTO();
heroDTO.setId("baiqi");
heroDTO.setName("白起");
Message<String> msgs = MessageBuilder.withPayload(JSON.toJSONString(heroDTO))
//设置消息KEYS,一般是数据的唯一ID,主要用于在仪表盘中方便搜索
.setHeader("KEYS", "777")
.build();
//10秒后才能消费这条消息
SendResult sendResult = extRocketMQTemplate.syncSendDelayTimeSeconds("topicG".concat(":tank"), msgs, 10L);
log.info(sendResult.toString());
}
6 批量发送
@GetMapping("/syncSendBatchMessage")
@ApiOperation(value = "批量发送消息")
@ApiOperationSupport(order = 8)
public void syncSendBatchMessage() {
List<HeroDTO> heroList = new ArrayList<>();
HeroDTO h1 = new HeroDTO();
h1.setId("geya");
h1.setName("戈娅");
heroList.add(h1);
HeroDTO h2 = new HeroDTO();
h2.setId("direnjie");
h2.setName("狄仁杰");
heroList.add(h2);
List<Message> msgs = new ArrayList<Message>();
for (HeroDTO hero : heroList){
Message<String> message = MessageBuilder.withPayload(JSON.toJSONString(hero))
.setHeader("KEYS", hero.getId())
.build();
msgs.add(message);
}
SendResult sendResult = extRocketMQTemplate.syncSend("topicH".concat(":shooter"), msgs);
log.info(sendResult.toString());
}
第三步、创建消费者
消费者和生产者通常不在一个应用里,消费者的代码很简单,新建一个继承RocketMQListener监听器
配置文件和相关代码
rocketmq:
# NameServer
name-server: 127.0.0.1:9876
# 默认的消息组
producer:
group: groupTest
@Component
@RocketMQMessageListener(consumerGroup = "group8", topic = "topicH",consumeMode = ConsumeMode.ORDERLY,selectorExpression = "shooter")
@Slf4j
public class ConsumerListener8 implements RocketMQListener<String> {
@Override
public void onMessage(String message) {
log.info("Received message : " + message);
}
}
接下来了解一下@RocketMQMessageListener这个注解
- topic:主题,指消费者组订阅的消息服务
- consumerGroup:消费者组,一个组可以有多个消费者,主要的作用是集群模式负载均衡的实现,广播模式的通知的实现
- consumeModel:控制消费模式,你可以选择并发或有序接收消息
- messageModel:控制消息模式,广播模式-所有消费者都能接收到信息, 集群模式:无论有多少个消费者,只有一个消费者能够接收到信息,也就是说消息一旦被消费了,其它消费者就不能消费该条消息
- selectorExpression:选择哪个标签(tag)下的信息,默认是消费该主题下的所有信息
排坑
问题1:MQClientException: No route info of this topic, mytopic
问题描述:我是在window上使用RocketMQ,环境配置,文件配置,MQ启动,一系列操作都成功后,然后在项目中使用MQ的时候报了这个错!!!
答:改变broker启动方式:用命令行启动并指定端口和自动创建Topic。
start mqbroker.cmd -n 127.0.0.1:9876 autoCreateTopicEnable=true
问题2:有些消息dashboard看到2条
回答1:重复查询的问题是仪表板的源代码,这可能是5.1.1版本之后的不兼容造成的。建议手动更改源代码:
Org. apache. locketmq. dashboard. service. impl. Message Service Impl # queryFirstMessage Page
Line 271 should read:
Long maxOffset=consumer. searchOffset (messageQueue, query. getEnd());
回答2:是的,此回答整理自钉群“群2-Apache RocketMQ 中国开发者钉钉群”