PS: 在学习该篇文章的快速入门之前, 部署了RocketMQ 了解了一些RocketMQ的基础知识.
一 搭建一个SrpingBoot项目
为了方便测试,演示效果,这里已经把一个简单的SpringBoot项目搭建好. 我们可以自己搭建一个, 也可以免费下载该篇文章中附带的项目. 附带的项目里面有本次入门案例中所有请求示例.
二 添加RocketMQ 依赖
<!--rocketMq依赖-->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.1</version>
</dependency>
三 配置application.yml文件
我SpringBoot使用的是 application.yml. 同样的道理. 用其他方式配置也行.
#@Author https://blog.csdn.net/c20611
server:
port: 8081 # 配置启动端口号
#配置RocketMQ
rocketmq:
#MQ地址 集群 127.0.0.0:9876;127.0.0.0:9876;127.0.0.0:9876
name-server: 127.0.0.0:9876
producer:
#MQ组名
group: "service-producer"
#消息达到4096字节的时候,消息就会被压缩。默认就是4096,有利于网络传输,提升性能。
compress-message-body-threshold: 4096
#消息发送的超时时间,毫米级别,默认为3S
send-message-timeout: 3000
#同步消息发送失败重试次数
retry-times-when-send-failed: 3
#在内部发送失败时是否重试其他代理。 源码:setRetryAnotherBrokerWhenNotStoreOK,就是指:发送到broker-a失败是否发送到broker-b。这个参数在有多个broker才生效。
retry-next-server: true
#异步消息发送失败重试的次数
retry-times-when-send-async-failed: 3
consumer:
#消费者名字
group: "service-consumer"
#批量拉取消息数量
pull-batch-size: 10
message-model: CLUSTERING
selector-expression: "*"
四 创建消费者
我们先创建消费者是为了接下来生产者 ,生产的消息有地方消费. 要不然我们也不好看出演示结果.
/**
* 普通消费者
* @Author https://blog.csdn.net/c20611
* @Date 2024/10/29 17:21
*/
@Component
@RocketMQMessageListener(topic = "CSDN-topic", consumerGroup = "CSDN-consumer", selectorExpression = "CSDN-tag")
public class RocketMQConsumerController implements RocketMQListener<MessageExt> {
private static final Logger log = LoggerFactory.getLogger(RocketMQProducerController.class);
@Override
public void onMessage(MessageExt messageExt) {
log.info("消费者开始消费");
byte[] body = messageExt.getBody();
log.info(new String(body, StandardCharsets.UTF_8));
}
}
4.1 RocketMQListener 介绍
- 代码中 implements @RocketMQListener这个是RocketMQ提供了的消费者监听器,MessageExt是消息对象Message的子类 。这里的泛型对应生产者的消息类型,可以直接是消息的对象类型。比如RocketMQListener<String>. 这个MessageExt只是rocketmq..common.message中的一个类.
- implements @RocketMQListener 实现了人家MQ的接口, 那就得引入人家的方法. onMessage消费的消息也是在这里处理的.
4.2 RocketMQMessageListener
- @RocketMQMessageListener 与上面的 RocketMQListener配合就可以实现简单的消息消费了.
- @RocketMQMessageListener: 消息监听的注解,提供了常用的四个属性:
consumerGroup :消费者的组名.
topic : 主题,对应生产者发送消息指定的destination拼接的主题
selectorExpression :消息选择表达式,其实就是制定消费什么tags ; 可以是固定一
个值,如果是 * 是消费该topic下的所有消息 ;或者可以使用: tag1 | tag2 的方式 消费多个消息,除此之外还支持使用SQL进 行消息过滤,这种方式可以实现对消息的复杂过滤。SQL过滤表 达式中支持多种常量类型与运算符。比如:and ; or ; not ; IS NULL 或者 IS NOT NULL 等等。
messageModel :消息的消费模式,默认是CLUSTERING集群,还支 持BROADCASTING广播
五 创建生产者
在RocketMQ基础知识篇中说到, RocketMQ的消息类型有. 单项消息,异步消息,同步消息,普通消息,批量消息,顺序消息,延迟消息,事务消息,请求应答消息,重试消息,死信消息 .因为是入门篇章, 我们就选择几种消息类型实操感受一下 消息的生产与消费的过程.
5.1 同步消息
/**
* 生产者
* @Author https://blog.csdn.net/c20611
* @Date 2024/10/29 17:20
*/
@Api(tags = "消息服务端")
@RequestMapping("/producer")
@RestController
public class RocketMQProducerController {
private static final Logger log = LoggerFactory.getLogger(RocketMQProducerController.class);
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* 同步消息
*/
@RequestMapping("/ProducerMq1")
public void ProducerMQ1(){
String stringTopic = "CSDN-topic:CSDN-tag";
String payloadStr = "你好 CSDN";
SendResult sendResult = rocketMQTemplate.syncSend(stringTopic, payloadStr);
if (!sendResult.getSendStatus().equals(SendStatus.SEND_OK)) {
log.error("发送失败");
}else {
log.info("MQ同步发送:{},返回结果:{}", stringTopic, sendResult);
}
}
}
在这里@RequestMapping, @RestController 这些注解就不多解释了. 会用SpringBoot的一定知道. 这里也就有一个陌生面孔RocketMQTemplate.
RocketMQTemplate是org.apache.rocketmq.spring.core 包下的一个重要类. 它用于简化Spring框架中与RocketMQ消息系统的交互, 支持消息的发送, 接收, 事务操作等. 核心功能如下: 发送异步消息; 发送同步消息; 发送单向消息; 发送延时消息; 发送顺序消息; 发送事务消息; 订阅并接收消息;
同步消息, 意味着发送消息后会等待RocketMQ的返回结果 . 同步消息是最常见的发送方式, 适合消息可靠要求较高的场景使用. 但是阻塞也会导致性能降低. 使用rocketMQTemplate.syncSend来完成.
操作演示
启动SpringBoot项目
发送请求
http://localhost:8081/producer/ProducerMq1
控制台收到打印结果
可以看出,我们的同步消息发出并且, 被消费者消费掉打印了" 你好 CSDN"
5.2 异步消息
/**
* 生产者
* @Author https://blog.csdn.net/c20611
* @Date 2024/10/29 17:20
*/
@Api(tags = "消息服务端")
@RequestMapping("/producer")
@RestController
public class RocketMQProducerController {
private static final Logger log = LoggerFactory.getLogger(RocketMQProducerController.class);
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* 异步消息
* @throws Exception
*/
@RequestMapping("/asyncProducerMQ2")
public void asyncProducerMQ2() throws Exception{
String stringTopic = "CSDN-topic:CSDN-tag";
Message<String> message = MessageBuilder.withPayload("哈喽!这是一条异步消息").build();
rocketMQTemplate.asyncSend(stringTopic, message, new SendCallback() {
/**
* 成功
* @param sendResult 发送结果
*/
@Override
public void onSuccess(SendResult sendResult) {
if (!sendResult.getSendStatus().equals(SendStatus.SEND_OK)) {
log.error("发送失败");
}else {
log.info("MQ异步发送:{},返回结果:{}", stringTopic, sendResult);
}
}
/**
* 异常
* @param throwable
*/
@Override
public void onException(Throwable throwable) {
log.info("发送异常!!!!!!");
throwable.printStackTrace();
}
});
Thread.sleep(5000);
}
}
异步消息, 就是发送消息者无需等待结果, 可以直接发送第二条消息. 可以通过回调的方式来获取到消息结果, 消息可靠性高, 性能高. 使用rocketMQTemplate.asyncSend. 来完成.
操作演示
启动SpringBoot后, 发送请求
http://localhost:8081/producer/asyncProducerMQ2
控制台收到打印结果
可以看出消费者消费了一条消息, 并且打印出'哈喽!这是一条异步消息". 异步消息在这里处理,调用方式由rocketMQTemplate.syncSend, 变成 rocketMQTemplate.asyncSend之外, 我们感受到的比较少. 这个异步与同步最大的区别就在于是否等待服务器响应, 再实际并发场景中感受的会比较深. 入门篇就不多演示.
5.3 单向消息
/**
* 生产者
* @Author https://blog.csdn.net/c20611
* @Date 2024/10/29 17:20
*/
@Api(tags = "消息服务端")
@RequestMapping("/producer")
@RestController
public class RocketMQProducerController {
private static final Logger log = LoggerFactory.getLogger(RocketMQProducerController.class);
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* 发送单向消息
*/
@RequestMapping("/oneProducerMQ3")
public void oneProducerMQ3() {
String stringTopic = "CSDN-topic:CSDN-tag";
Message<String> message = MessageBuilder.withPayload("哈喽!我是单向消息").build();
rocketMQTemplate.sendOneWay(stringTopic, message);
log.info("单向消息发送");
}
}
所谓的单向消息, 就是发送者发送完消息就不用管了. 不用等待Brock的结果返回, 同时Brock 也不会去返回了. 该方式性能最高, 但消息可靠性底. 使用的是
rocketMQTemplate.sendOneWay
操作演示
启动SpringBoot后, 发送请求
http://localhost:8081/producer/oneProducerMQ3
控制台收到打印结果
可以看到,消费者已经把我们消息给消费了并且再控制台中打印出"哈喽!我是单向消息", 同其他消息发送有个最大的区别, 发送后没有打印返回. 有的人疑问, 你直接代码上没有写返回, 😂. 这里拿到我的代码后可以使用rocketMQTemplate.sendOneWay 试一下, 看支持返回不
5.4 延迟消息
/**
* 生产者
* @Author https://blog.csdn.net/c20611
* @Date 2024/10/29 17:20
*/
@Api(tags = "消息服务端")
@RequestMapping("/producer")
@RestController
public class RocketMQProducerController {
private static final Logger log = LoggerFactory.getLogger(RocketMQProducerController.class);
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* 延迟消息
*/
@RequestMapping("/deferredProducerMQ4")
public void deferredMessageMQ4() {
String stringTopic = "CSDN-topic:CSDN-tag";
Message<String> message = MessageBuilder.withPayload("哈喽!我是延迟消息").build();
//发送延迟消息,单位毫秒,2秒超时,延迟30秒
SendResult sendResult = rocketMQTemplate.syncSend(stringTopic, message, 2000, 4);
if (!SendStatus.SEND_OK.equals(sendResult.getSendStatus())) {
System.err.println("发送失败");
}else {
log.info("延迟消息发送");
}
}
}
- 延迟消息, 见名知意. 就是消息写道Brock中后需要延迟一点过时间才可以被消费.
- 这里在RocketMQ中消息的延迟时间不能任意指定,而是由特定的等级(1 至18)来指定,分别有:messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h. 也就是指定1 就是延迟1s. 指定18延迟2h.
- 可以通过修改配置来增加级别,比如在mq安装目录的 broker.conf. 文件中增加messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h 2d 这个时候总共就有19个level。
操作演示
启动SpringBoot后, 发送请求
http://localhost:8081/producer/deferredProducerMQ4
控制台收到打印结果
图中可以看出消息发送于11:44 消费者开始消费是12:14. 我们代码中设置的延迟级别是4 也就是对应的30s. 这里延迟时间正好30s.