前言
本博文只讲述如何在Spring Boot工程中使用Rocket MQ,并不涉及原理,有需求者可跳转下方博文。
一 准备工作
1.依赖
很多文章在讲述整合Rocket MQ时都会使用原生API依赖。这么做固然可行,但大量的底层配置及复杂的操作代码不利于Rocket MQ在企业内的推广和项目的整体维护。
<!-- Rocket MQ客户端依赖(不推荐) -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.4.0</version>
</dependency>
推荐采用【rocketmq-spring-boot-starter】依赖。这是一个年轻的项目,2019年1月正式收纳于Maven中心仓库,截至2021年6月共7个版本。该项目完成了整合的大量底层工作,并提供了喜闻乐见的Spring起步依赖包:
<!-- Spring Boot工程Rocket MQ起步依赖(推荐) -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
2.配置
# Rocket MQ configuration
rocketmq:
// 命名服务器地址。
nameServer: http://localhost:9876
producer:
// 生产者组名称,此处直接使用服务名。
group: ${spring.application.name}
// 发送消息超时时间,默认3s(因此也可不设置)。
send-message-timeout: 3000
二 消费者
1.消费监听
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;
/**
* @Author: 说淑人
* @Description: consumerGroup:消费组名称。自定义且唯一,否则会报错。
* @Description: topic:主题。指定消费消息的主题。
* @Description: selectorExpression:筛选,无tag时可不设置。
* @Description: 指定消费消息的标签,不设置或为默认值(*)时消费topic下所有消息。
* @Description: 泛型:指定消费消息的类型。
*/
@Slf4j
@Component
@RocketMQMessageListener(consumerGroup = "consumerGroup",
topic = "topic", selectorExpression = "tag")
public class Consumer implements RocketMQListener<String> {
/**
* 处理消息
*
* @param message 消息
*/
@Override
public void onMessage(String message) {
Thread thread = Thread.currentThread();
log.info("线程【ID:" + thread.getId() + ",名称:" + thread.getName() + "】开始执行处理消息监听器.....");
log.info(message);
log.info("线程【ID:" + thread.getId() + ",名称:" + thread.getName() + "】结束执行处理消息监听器。");
}
}
2.消费模式
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;
/**
* @Author: 说淑人
* @Description: consumerGroup:消费组名称。自定义且唯一,否则会报错。
* @Description: topic:主题。指定消费消息的主题。
* @Description: selectorExpression:筛选,无tag时可不设置。
* @Description: 指定消费消息的标签,不设置或为默认值(*)时消费topic下所有消息。
* @Description: messageModel:消息模式。指定消费消息的模式。
* @Description: 泛型:指定消费消息的类型。
*/
@Slf4j
@Component
@RocketMQMessageListener(consumerGroup = "consumerGroup",
topic = "topic", selectorExpression = "tag",
// MessageModel.CLUSTERING:集群模式(默认);
// MessageModel.BROADCASTING:广播模式。
messageModel = MessageModel.BROADCASTING)
public class Consumer implements RocketMQListener<String> {
/**
* 处理消息
*
* @param message 消息
*/
@Override
public void onMessage(String message) {
Thread thread = Thread.currentThread();
log.info("线程【ID:" + thread.getId() + ",名称:" + thread.getName() + "】开始执行处理消息监听器.....");
log.info(message);
log.info("线程【ID:" + thread.getId() + ",名称:" + thread.getName() + "】结束执行处理消息监听器。");
}
}
三 简单发送
1.同步发送
/**
* 同步发送
*/
private void syncSend() {
// 终点:即消息的键。由topic和tag(可无)通过:连接而成,例topic:tag、topic。
String destination = "topic:tag";
// 消息:即消息的值。是要发送的内容,可为任意类型,此处用String。
String message = "Hello World";
// 方法一。
SendResult sendResult = rocketMQTemplate.syncSend(destination, MessageBuilder.withPayload(message).build());
// 方法二。
sendResult = rocketMQTemplate.syncSend(destination, message);
// 以上两种方法都可完成发送,其中方法一是方法二的底层方法。本人习惯用第二种,因为操作方便。
}
2.异步发送
/**
* 异步发送
*/
private void asyncSend() {
// 终点:即消息的键。由topic和tag(可无)通过:连接而成,例topic:tag、topic。
String destination = "topic:tag";
// 消息:即消息的值。是要发送的内容,可为任意类型,此处用String。
String message = "Hello World";
// 发送回调接口对象:用于异步处理发送结果。
SendCallback sendCallback = new SendCallback() {
/**
* 处理成功
* @param sendResult 发送结果对象
*/
@Override
public void onSuccess(SendResult sendResult) {
// 发送成功时执行逻辑。
}
/**
* 处理成功
* @param throwable 错误对象
*/
@Override
public void onException(Throwable throwable) {
// 发送失败时执行逻辑。一般是将失败数据入库,采用定时的方式尝试再次发送。
}
};
// 方法一。
rocketMQTemplate.asyncSend(destination, MessageBuilder.withPayload(message).build(), sendCallback);
// 方法二。
rocketMQTemplate.asyncSend(destination, message, sendCallback);
// 以上两种方法都可完成发送,其中方法一是方法二的底层方法。本人习惯用第二种,因为操作方便。
}
3.单向发送
/**
* 单向发送
*/
private void sendOneWay() {
// 终点:即消息的键。由topic和tag(可无)通过:连接而成,例topic:tag、topic。
String destination = "topic:tag";
// 消息:即消息的值。是要发送的内容,可为任意类型,此处用String。
String message = "Hello World";
// 方法一。
rocketMQTemplate.sendOneWay(destination, MessageBuilder.withPayload(message).build());
// 方法二。
rocketMQTemplate.sendOneWay(destination, message);
// 以上两种方法都可完成发送,其中方法一是方法二的底层方法。本人习惯用第二种,因为操作方便。
}
四 顺序发送
/**
* 顺序发送
*/
private void orderSend() {
// 同步顺序发送。
String destination = "topic:tag";
String message = "Hello World";
String key = "key";
// 方法一。
SendResult sendResult = rocketMQTemplate.syncSendOrderly(destination, MessageBuilder.withPayload(message).build(), key);
// 方法二。
sendResult = rocketMQTemplate.syncSendOrderly(destination, message, key);
// 异步顺序发送。
SendCallback sendCallback = new SendCallback() {
/**
* 处理成功
* @param sendResult 发送结果对象
*/
@Override
public void onSuccess(SendResult sendResult) {
// 发送成功时执行逻辑。
}
/**
* 处理成功
* @param throwable 错误对象
*/
@Override
public void onException(Throwable throwable) {
// 发送失败时执行逻辑。一般是将失败数据入库,采用定时的方式尝试再次发送。
}
};
// 方法一。
rocketMQTemplate.asyncSendOrderly(destination, MessageBuilder.withPayload(message).build(), key, sendCallback);
// 方法二。
rocketMQTemplate.asyncSendOrderly(destination, message, key, sendCallback);
// 单向顺序发送。
// 方法一。
rocketMQTemplate.sendOneWayOrderly(destination, MessageBuilder.withPayload(message).build(), key);
// 方法二。
rocketMQTemplate.sendOneWayOrderly(destination, message, key);
}
五 批量发送
/**
* 批量发送
*/
private void batchSend() {
// 同步批量发送。
String destination = "topic:tag";
String messageOne = "Hello World";
String messageTwo = "Goodbye World";
// 消息列表。
List<String> messages = new ArrayList<>();
messages.add(messageOne);
messages.add(messageTwo);
SendResult sendResult = rocketMQTemplate.syncSend(destination, messages);
// 异步批量发送。
SendCallback sendCallback = new SendCallback() {
/**
* 处理成功
* @param sendResult 发送结果对象
*/
@Override
public void onSuccess(SendResult sendResult) {
// 发送成功时执行逻辑。
}
/**
* 处理成功
* @param throwable 错误对象
*/
@Override
public void onException(Throwable throwable) {
// 发送失败时执行逻辑。一般是将失败数据入库,采用定时的方式尝试再次发送。
}
};
rocketMQTemplate.asyncSend(destination, messages, sendCallback);
// 单向发送无批量发送功能。
}
六 延时发送
/**
* 延时发送
*/
private void scheduleSend() {
// 同步延时发送。
String destination = "topic:tag";
String message = "Hello World";
String key = "key";
// 超时时间:超出该时间后会报超时异常。
long timeout = 3000L;
// 延时等级:1~18,分别延时1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h。
int delayLevel = 3;
// 方法一。
SendResult sendResult = rocketMQTemplate.syncSend(destination, MessageBuilder.withPayload(message).build(), timeout, delayLevel);
// 异步延时发送。
SendCallback sendCallback = new SendCallback() {
/**
* 处理成功
* @param sendResult 发送结果对象
*/
@Override
public void onSuccess(SendResult sendResult) {
// 发送成功时执行逻辑。
}
/**
* 处理成功
* @param throwable 错误对象
*/
@Override
public void onException(Throwable throwable) {
// 发送失败时执行逻辑。一般是将失败数据入库,采用定时的方式尝试再次发送。
}
};
rocketMQTemplate.asyncSend(destination, MessageBuilder.withPayload(message).build(), sendCallback, timeout, delayLevel);
// 单向发送无延时发送功能。
}
七 事务发送及消费
【rocketmq-spring-boot-starter】依赖目前尚不支持事务发送。