<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.apache.rocketmqgroupId>
<artifactId>rocketmq-spring-boot-starterartifactId>
<version>2.0.2version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.25version>
dependency>
<dependency>
<groupId>org.apache.rocketmqgroupId>
<artifactId>rocketmq-spring-boot-starterartifactId>
<version>2.2.1version>
dependency>
dependencies>
spring:
application:
name: rocketmq-boot
server:
port: 8083
# rocketmq配置
rocketmq:
name-server: http://127.1.1.1:9876
#自定义的组名称
producer:
group: producer_test
#消息发送超时时长
send-message-timeout: 5000
package com.study.producer;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class Demo01_TestProducer {
private static final Logger log = LoggerFactory.getLogger(Demo01_TestProducer.class);
@Resource
RocketMQTemplate rocketmqTemplate;
public void send() {
log.info("开始发送...");
for (int i=1; i <= 20;i++){
String text = "测试发送" + i;
Message<String> message = MessageBuilder.withPayload(text).build();
rocketmqTemplate.send("TEST_MESSAGE", message);
}
log.info("已发送...");
}
}
package com.study.consumer;
import com.study.producer.Demo01_TestProducer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
@RocketMQMessageListener(topic = "TEST_MESSAGE", consumerGroup = "test_group")
public class Demo01_TestConsumer implements RocketMQListener<String> {
private static final Logger log = LoggerFactory.getLogger(Demo01_TestConsumer.class);
@Override
public void onMessage(String message) {
log.info("TestConsumer - 接受到消息:" + message);
}
}
@GetMapping("sendDemo01TestPro")
private void sendDemo01TestPro(){
testProducer.send();
}
package com.study.producer;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 基本消息样例
* 1,同步消息:这种可靠性同步地发送方式使用的比较广泛,比如:重要的消息通知,短信通知。
* 2,异步消息:用在对响应时间敏感的业务场景,即发送端不能容忍长时间地等待Broker的响应。
* 3,单向发送消息:这种方式主要用在不关心发送结果的场景,例如日志发送。
*/
@Service
public class Demo02_BasicsProducer {
@Resource
RocketMQTemplate rocketMQTemplate;
private static final Logger log = LoggerFactory.getLogger(Demo02_BasicsProducer.class);
/**
* 同步消息: 这种可靠性同步地发送方式使用的比较广泛,比如:重要的消息通知,短信通知。
*/
public void sync() {
String text = "基本信息案例-同步发送" + System.currentTimeMillis();
log.info(text);
for (int a = 1; a <= 10; a++) {
rocketMQTemplate.syncSend("SYNC_TOPIC", text+"----"+a);
}
log.info("同步发送-已发送...");
}
/**
* 异步消息:异步消息通常用在对响应时间敏感的业务场景,即发送端不能容忍长时间地等待Broker的响应。
*/
public void async() {
String text = "基本信息案例-异步发送" + System.currentTimeMillis();
log.info(text);
for (int a = 1; a <= 10; a++) {
rocketMQTemplate.asyncSend("ASYNC_TOPIC", text + ",ID:" + a, new SendCallback() {
// SendCallback接收异步返回结果的回调
// 成功发送
@Override
public void onSuccess(SendResult sendResult) {
log.info("异步发送 - 发送成功");
}
// 发送失败
@Override
public void onException(Throwable throwable) {
log.info("异步发送 - 发送失败");
throwable.printStackTrace();
}
});
}
log.info("异步发送-已发送...");
}
/**
* 单向发送消息:这种方式主要用在不特别关心发送结果的场景,例如日志发送。
*/
public void oneWay() {
String text = "基本信息案例-单向发送" + System.currentTimeMillis();
log.info(text);
for (int a = 1; a <= 10; a++) {
rocketMQTemplate.sendOneWay("ONEWAY_TOPIC", text+"----"+a);
}
rocketMQTemplate.sendOneWay("ONEWAY_TOPIC", text);
log.info("单向发送-已发送...");
}
}
package com.study.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* 异步消息
*/
@Component
@RocketMQMessageListener(selectorExpression = "", topic = "ASYNC_TOPIC", consumerGroup = "async_group")
public class Demo02_Basics_Async_Consumer implements RocketMQListener<String> {
private static final Logger log = LoggerFactory.getLogger(Demo02_Basics_Async_Consumer.class);
/**
*
* @param message
*/
@Override
public void onMessage(String message) {
log.info("异步消息-接受到消息:" + message);
}
}
package com.study.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* 单向发送消息
*/
@Component
@RocketMQMessageListener(selectorExpression = "", topic = "ONEWAY_TOPIC", consumerGroup = "oneway_group")
public class Demo02_Basics_Oneway_Consumer implements RocketMQListener<String> {
private static final Logger log = LoggerFactory.getLogger(Demo02_Basics_Oneway_Consumer.class);
/**
*
* @param message
*/
@Override
public void onMessage(String message) {
log.info("单向发送消息-接受到消息:" + message);
}
}
package com.study.consumer;
import com.study.producer.Demo02_BasicsProducer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* 同步消息
*/
@Component
@RocketMQMessageListener(selectorExpression = "", topic = "SYNC_TOPIC", consumerGroup = "sync_group")
public class Demo02_Basics_Sync_Consumer implements RocketMQListener<String> {
private static final Logger log = LoggerFactory.getLogger(Demo02_Basics_Sync_Consumer.class);
/**
*
* @param message
*/
@Override
public void onMessage(String message) {
log.info("同步消息-接受到消息:" + message);
}
}
/**
* 异步消息
*/
@GetMapping("sendAsync")
private String sendAsync(){
demo02_basicsProducer.async();
return"异步发送 - 发送成功";
}
/**
* 单向发送消息
*/
@GetMapping("sendOneway")
private String sendOneway(){
demo02_basicsProducer.oneWay();
return"单向发送消息 - 发送成功";
}
/**
* 同步消息
*/
@GetMapping("sendSync")
private String sendSync(){
demo02_basicsProducer.sync();
return"同步消息 - 发送成功";
}
http://localhost:8083/sendAsync
http://localhost:8083/sendOneway
http://localhost:8083/sendSync
消息有序指的是可以按照消息的发送顺序来消费(FIFO),rocketmq可以严格的保证消息有序
package com.study.producer;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
/**
* 顺序消息
*/
@Service
public class Demo03_OrderProducer {
@Resource
RocketMQTemplate rocketMQTemplate;
private static final Logger log = LoggerFactory.getLogger(Demo03_OrderProducer.class);
public void order() {
log.info("顺序消息");
try {
for (int i = 1; i <= 10; i++) {
int num = (int) (Math.random() * 10000);
// 设置一个延时,表示同一个消息先后进入到队形中
TimeUnit.MILLISECONDS.sleep(50);
log.info("顺序消息,ID:" + num);
// 第一个参数为topic,第二个参数为内容,第三个参数为Hash值,不同hash值在不同的队列中
rocketMQTemplate.syncSendOrderly("ORDER_TOPIC", "顺序消息,ID:" + num, "order");
}
log.info("已发送...");
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.study.consumer;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
@RocketMQMessageListener(topic = "ORDER_TOPIC", consumerGroup = "ORDER_TOPIC", consumeMode = ConsumeMode.ORDERLY)
public class Demo03_OrderConsumer implements RocketMQListener<String> {
private static final Logger log = LoggerFactory.getLogger(Demo03_OrderConsumer.class);
@Override
public void onMessage(String message) {
log.info("顺序消息生产-接受到消息:" + message);
}
}
@GetMapping("/sendOrder")
public Object order() {
demo03_orderProducer.order();
return "发送顺序消息";
}
通过设置延时等级,实现消费者延时消费数据,比如电商里,提交了一个订单就可以发送一个延时消息,1h后去检查这个订单的状态,如果还是未付款就取消订单释放库存。
package com.study.producer;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class Demo04_ScheduledProducer {
private static final Logger log = LoggerFactory.getLogger(Demo04_ScheduledProducer.class);
/**
* 测试发送将参数topic定死,实际开发写入到配置文件
*/
@Resource
RocketMQTemplate rocketMQTemplate;
public void scheduled() {
String text = "延时消息"+ System.currentTimeMillis();
log.info(text);
// 设置延时等级2,这个消息将在5s之后发送
// 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
Message<String> message = MessageBuilder.withPayload(text).build();
rocketMQTemplate.syncSend("SCHEDULED_TOPIC", message, 1000, 4);
log.info("已发送...");
}
}
package com.study.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
@RocketMQMessageListener(topic = "SCHEDULED_TOPIC", consumerGroup = "SCHEDULED_TOPIC")
public class Demo04_ScheduledConsumer implements RocketMQListener<String> {
private static final Logger log = LoggerFactory.getLogger(Demo04_ScheduledConsumer.class);
/**
* 测试接收将参数topic定死,实际开发写入到配置文件
* @param message
*/
@Override
public void onMessage(String message) {
log.info("延时消息-接受到消息:" + message);
}
}
/**
* 延时消息
* @return
*/
@GetMapping("/sendScheduled")
public Object scheduled() {
scheduledProducer.scheduled();
return "发送延时消息";
}
http://localhost:8083/sendScheduled
一个应用尽可能用一个Topic,消息子类型用tag来标识,tag可以由应用自由设置。 在使用rocketmqTemplate发送消息时,通过设置发送方法的destination参数来设置消息的目的地,destination的格式为topicName:tagName,:前面表示topic的名称,后面表示tag名称。
package com.study.producer;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class Demo05_TagProducer {
private static final Logger log = LoggerFactory.getLogger(Demo05_TagProducer.class);
@Resource
RocketMQTemplate rocketMQTemplate;
public void tag() {
String text = "标签过滤消息," + System.currentTimeMillis();
log.info(text);
for (int i = 1; i <= 10; i++) {
// 任何类型的send方法均可以指定TAG,默认可以不指定则为*
Message<String> message = MessageBuilder.withPayload(text+"-----"+i).build();
rocketMQTemplate.syncSend("TAG_TOPIC:TAG-A", message);
}
log.info("已发送...");
}
}
package com.study.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
@RocketMQMessageListener(selectorExpression = "TAG-A||TAG-B", topic = "TAG_TOPIC", consumerGroup = "TAG_TOPIC")
public class Demo05_TagConsumer implements RocketMQListener<String> {
private static final Logger log = LoggerFactory.getLogger(Demo05_TagConsumer.class);
/**
*
* @param message
*/
@Override
public void onMessage(String message) {
log.info("标签过滤消息-接受到消息:" + message);
}
}
@GetMapping("/sendTag")
public Object tag() {
// TAG过滤
tag.tag();
return "指定标签消息";
}
生产者进行消息发送时可以一次发送多条消息,这可以大大提升Producer的发送效率。
默认情况下,一批发送的消息总大小不能超过4MB字节,如果想超出该值,有两种解决
package com.study.splitter;
import org.springframework.messaging.Message;
import java.util.Iterator;
import java.util.List;
public class MessageSplitter implements Iterator<List<Message>> {
/**
* 分割数据大小
*/
private final int sizeLimit = 1024 * 1024;
;
/**
* 分割数据列表
*/
private final List<Message> messages;
/**
* 分割索引
*/
private int currIndex;
public MessageSplitter(List<Message> messages) {
this.messages = messages;
// 保证单条数据的大小不大于sizeLimit
messages.forEach(m -> {
if (m.toString().length() > sizeLimit) {
throw new RuntimeException("单挑消息不能大于" + sizeLimit + "B");
}
});
}
@Override
public boolean hasNext() {
return currIndex < messages.size();
}
@Override
public List<Message> next() {
int nextIndex = currIndex;
int totalSize = 0;
for (; nextIndex < messages.size(); nextIndex++) {
Message t = messages.get(nextIndex);
totalSize = totalSize + t.toString().length();
if (totalSize > sizeLimit) {
break;
}
}
List<Message> subList = messages.subList(currIndex, nextIndex);
currIndex = nextIndex;
return subList;
}
}
package com.study.producer;
import com.study.splitter.MessageSplitter;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Service
public class Demo06_BatchProducer {
private static final Logger log = LoggerFactory.getLogger(Demo06_BatchProducer.class);
/**
* 测试发送将参数topic定死,实际开发写入到配置文件
*/
@Resource
RocketMQTemplate rocketMQTemplate;
public void batch() {
String text = "批量消息";
log.info(text);
List<Message> messageList = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
messageList.add(MessageBuilder.withPayload(text + "--" + i).build());
}
log.info("开始发送...");
//把大的消息分裂成若干个小的消息
MessageSplitter splitter = new MessageSplitter(messageList);
while (splitter.hasNext()) {
List<Message> nextList = splitter.next();
SendResult result = rocketMQTemplate.syncSend("BATCH_TOPIC", nextList);
if (result.getSendStatus() == SendStatus.SEND_OK) {
log.info("发送批量消息成功!消息ID为:{}", result.getMsgId());
} else {
log.info("发送批量消息失败!消息ID为:{},消息状态为:{}", result.getMsgId(), result.getSendStatus());
}
}
log.info("已发送...");
}
}
package com.study.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
@RocketMQMessageListener(topic = "BATCH_TOPIC", consumerGroup = "BATCH_TOPIC")
public class Demo06_BatchComsumer implements RocketMQListener<String> {
private static final Logger log = LoggerFactory.getLogger(Demo06_BatchComsumer.class);
/**
*
* @param message
*/
@Override
public void onMessage(String message) {
log.info("批量消息-接受到消息:" + message);
}
}
@GetMapping("/sendBatch")
public Object batch() {
// 批量消息样例
batchProducer.batch();
return "批量消息样例";
}
http://localhost:8083/sendBatch
生产者通过sendAndReceive发送消息,消费者需要实现rocketmqReplyListener
如果连续通过sendAndReceive发送消息,生产者必须收到消费者的回复才能发送下一条消息。
package com.study.producer;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class Demo07_ReplyProducer {
private static final Logger log = LoggerFactory.getLogger(Demo07_ReplyProducer.class);
@Resource
RocketMQTemplate rocketMQTemplate;
public void reply() {
// 如果消费者没有回馈消息,则不会发送下一条消息
for (int i = 1; i <= 10; i++) {
String text = "回馈消息" + "--" + i;
log.info("发送" + text);
Object obj = rocketMQTemplate.sendAndReceive("REPLY_TOPIC", text, String.class);
log.info("消费者返回的消息:" + obj);
}
}
}
package com.study.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQReplyListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
@RocketMQMessageListener(topic = "REPLY_TOPIC", consumerGroup = "REPLY_TOPIC")
public class Demo07_ReplyConsumer implements RocketMQReplyListener<String, byte[]> {
private static final Logger log = LoggerFactory.getLogger(Demo07_ReplyConsumer.class);
@Override
public byte[] onMessage(String message) {
log.info("接受到消息:" + message);
// 返回消息到生成者
return ("返回消息到生产者").getBytes();
}
}
@GetMapping("/sendReply")
public Object reply() {
// 消息事务
replyProducer.reply();
return "回馈消息样例";
}