官网
参考:
https://rocketmq.apache.org/zh/docs/quickStart/02quickstart
https://rocketmq.apache.org/zh/docs/deploymentOperations/15deploy
64位linux系统
64位jdk1.8+=
maven3.2+=
# 自定义存放目录,并上传文件
cd /opt/rocketmq5/
# 解压
unzip rocketmq-all-5.0.0-bin-release.zip
# 添加环境变量
vim /etc/profile
# 增加以下配置
export ROCKETMQ_HOME=/opt/rocketmq5/rocketmq-all-5.0.0-bin-release
export PATH=$ROCKETMQ_HOME/bin:$PATH
source /etc/profile
# 根据需求修改rocketmq启动内存大小,避免内存溢出,如为虚拟机测试可调小一点,生产环境则根据情况调大或调小
# 修改rocketmq安装目录下的文件:bin/runserver.sh、bin/runbroker.sh
runserver.sh修改参考:
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn256m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
runbroker.sh修改参考:
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m"
# 启动NameServer
nohup sh /opt/rocketmq5/rocketmq-all-5.0.0-bin-release/bin/mqnamesrv > /opt/rocketmq5/rocketmq-all-5.0.0-bin-release/nohup.out 2>&1 &
# 启动Broker+Proxy
nohup sh /opt/rocketmq5/rocketmq-all-5.0.0-bin-release/bin/mqbroker -n localhost:9876 --enable-proxy > /opt/rocketmq5/rocketmq-all-5.0.0-bin-release/broker.out 2>&1 &
# 关闭rocketmq服务
#关闭proxy
sh /opt/rocketmq5/rocketmq-all-5.0.0-bin-release/bin/mqshutdown proxy
# 关闭NameServer
sh /opt/rocketmq5/rocketmq-all-5.0.0-bin-release/bin/mqshutdown namesrv
#JPS命令查看java进程
jps
# 测试
# 生产消息
sh tools.sh org.apache.rocketmq.example.quickstart.Producer
# 消费消息
sh tools.sh org.apache.rocketmq.example.quickstart.Consumer
vim /etc/sysconfig/iptables
# 增加下面配置开放端口
-A INPUT -p tcp -m state --state NEW -m tcp --dport 9876 -j ACCEPT
# 重启服务
systemctl restart iptables.service
# 检查开放情况
iptables -L -n
<!-- https://mvnrepository.com/artifact/org.apache.rocketmq/rocketmq-client-java -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client-java</artifactId>
<version>5.0.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
package org.rocketmq.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author zd
* @date 2023/1/31 11:23
* @description 属性配置
*/
@ConfigurationProperties(prefix = "rocketmq")
public class RocketMQProperties {
/**
* rocketmq name server addr
*/
private String nameServer;
private Producer producer;
public String getNameServer() {
return nameServer;
}
public void setNameServer(String nameServer) {
this.nameServer = nameServer;
}
public Producer getProducer() {
return producer;
}
public void setProducer(Producer producer) {
this.producer = producer;
}
public static class Producer {
/**
* Group name of producer.
*/
private String group;
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
}
}
# 对应的yml文件rocketmq配置
rocketmq:
name-server: 192.168.88.7:9876
producer:
# 生产者分组
group: MY_PRODUCER_GROUP
package org.rocketmq.config;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionListener;
import org.apache.rocketmq.client.producer.TransactionMQProducer;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageExt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author zd
* @date 2023/2/2 9:38
* @description 生产者包装
*/
public class RocketMQProducer implements Closeable {
private static final Logger log = LoggerFactory.getLogger(RocketMQProducer.class);
private DefaultMQProducer defaultMQProducer;
private TransactionMQProducer transactionMQProducer;
private String namesrvAddr;
private String produceGroup;
private AtomicInteger transactionIndex = new AtomicInteger(0);
private ConcurrentHashMap<String, Integer> localTrans = new ConcurrentHashMap<String, Integer>();
@Override
public void close() throws IOException {
if (this.defaultMQProducer != null) {
this.defaultMQProducer.shutdown();
log.info("A defaultMQProducer shutdown on namesrc {}", namesrvAddr);
}
if (this.transactionMQProducer != null) {
this.transactionMQProducer.shutdown();
log.info("A transactionMQProducer shutdown on namesrc {}", namesrvAddr);
}
}
public RocketMQProducer() {
}
public void initMQProducer() throws MQClientException{
this.initDefaultMQProducer();
this.initTransactionMQProducer();
}
/**
* 普通生产者
*/
private DefaultMQProducer initDefaultMQProducer() throws MQClientException {
this.defaultMQProducer = createDefaultMQProducer(new DefaultMQProducer(produceGroup));
this.defaultMQProducer.start();
log.info("A defaultMQProducer init on namesrc {}", namesrvAddr);
return this.defaultMQProducer;
}
/**
* 事务生产者
*/
private TransactionMQProducer initTransactionMQProducer() throws MQClientException {
this.transactionMQProducer = createTransactionMQProducer(new TransactionMQProducer("TS_" + produceGroup));
this.transactionMQProducer.start();
log.info("A transactionMQProducer init on namesrc {}", namesrvAddr);
return this.transactionMQProducer;
}
private DefaultMQProducer createDefaultMQProducer(DefaultMQProducer producer) {
producer.setNamesrvAddr(this.namesrvAddr);
return producer;
}
private TransactionMQProducer createTransactionMQProducer(TransactionMQProducer producer) {
producer.setNamesrvAddr(this.namesrvAddr);
// 事务消息处理线程池
ExecutorService executorService = new ThreadPoolExecutor(2, 5, 1000 * 60, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(2000), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("mq-transaction-msg-check-thread");
return thread;
}
});
producer.setExecutorService(executorService);
// 事务监听器
producer.setTransactionListener(new TransactionListener() {
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object o) {
// 执行生产者方本地事务
String transId = msg.getTransactionId();
log.info("执行本地事务, msgTransactionId={} %n", transId);
int value = transactionIndex.getAndIncrement();
int status = value % 3;
localTrans.put(transId, status);
if (status == 0) {
// Return local transaction with success(commit), in this case,
// this message will not be checked in checkLocalTransaction()
log.info("本地事务执行成功 msg {}", msg.getTransactionId());
return LocalTransactionState.COMMIT_MESSAGE;
}
if (status == 1) {
// Return local transaction with failure(rollback) , in this case,
// this message will not be checked in checkLocalTransaction()
log.info("本地事务执行失败 msg {}", msg.getTransactionId());
return LocalTransactionState.ROLLBACK_MESSAGE;
}
log.info("本地事务执行未知 msg {}", msg.getTransactionId());
return LocalTransactionState.UNKNOW;
}
// 回查本地事务执行情况
@Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
Integer status = localTrans.get(msg.getTransactionId());
LocalTransactionState retState = LocalTransactionState.COMMIT_MESSAGE;
if (null != status) {
switch (status) {
case 0:
retState = LocalTransactionState.COMMIT_MESSAGE;
break;
case 1:
retState = LocalTransactionState.ROLLBACK_MESSAGE;
break;
case 2:
retState = LocalTransactionState.UNKNOW;
break;
}
}
log.info("回查本地事务, msgTransactionId={}, TransactionState={} status={} %n",
msg.getTransactionId(), retState, status);
return retState;
}
});
return producer;
}
public DefaultMQProducer getDefaultMQProducer() {
return defaultMQProducer;
}
public TransactionMQProducer getTransactionMQProducer() {
return transactionMQProducer;
}
public void setNamesrvAddr(String namesrvAddr) {
this.namesrvAddr = namesrvAddr;
}
public void setProduceGroup(String produceGroup) {
this.produceGroup = produceGroup;
}
}
package org.rocketmq.config;
/**
* @Author: zd
* @Date: 2023-02-06 10:34
* @Description: 消费者实现接口
*/
public interface RocketMQListener {
void onMessage(String message);
}
package org.rocketmq.annotation;
import org.rocketmq.enums.ConsumeMode;
import org.rocketmq.enums.MessageModel;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author: zd
* @Date: 2023-02-06 10:04
* @Description: 定义消费者注解
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RocketMQMessageListener {
/**
* Consumers of the same role is required to have exactly same subscriptions and consumerGroup to correctly achieve
* load balance. It's required and needs to be globally unique.
*
*
* See here for further discussion.
*/
String consumerGroup();
/**
* Topic name.
*/
String topic();
/**
* Control which message can be select.
*/
String selectorExpression() default "*";
/**
* Control consume mode, you can choice receive message concurrently or orderly.
*/
ConsumeMode consumeMode() default ConsumeMode.CONCURRENTLY;
/**
* Control message mode, if you want all subscribers receive message all message, broadcasting is a good choice.
*/
MessageModel messageModel() default MessageModel.CLUSTERING;
}
package org.rocketmq.config;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;
import org.rocketmq.annotation.RocketMQMessageListener;
import org.rocketmq.enums.ConsumeMode;
import org.rocketmq.enums.MessageModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.Assert;
import java.io.Closeable;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
/**
* @Author: zd
* @Date: 2023-02-06 10:38
* @Description: 消费者封装
*/
public class RocketMQConsumer implements ApplicationContextAware, Closeable, SmartInitializingSingleton {
private static final Logger log = LoggerFactory.getLogger(RocketMQConsumer.class);
private ConfigurableApplicationContext context;
private String namesrvAddr;
private List<DefaultMQPushConsumer> consumerList = new ArrayList<>();
private AtomicLong counter = new AtomicLong(0);
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = (ConfigurableApplicationContext) applicationContext;
}
public void setNamesrvAddr(String namesrvAddr) {
this.namesrvAddr = namesrvAddr;
}
@Override
public void close() throws IOException {
for (DefaultMQPushConsumer consumer : consumerList) {
consumer.shutdown();
log.info("A defaultMQPushConsumer shutdown on namesrc {}", namesrvAddr);
}
}
@Override
public void afterSingletonsInstantiated() {
// 获取所有RocketMQMessageListener注解标记的bean
Map<String, Object> beans = this.context.getBeansWithAnnotation(RocketMQMessageListener.class)
.entrySet().stream().filter(entry -> !ScopedProxyUtils.isScopedTarget(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
// 注册
beans.forEach(this::registerConsumer);
}
private void registerConsumer(String beanName, Object bean) {
Class<?> clazz = bean.getClass();
RocketMQMessageListener annotation = clazz.getAnnotation(RocketMQMessageListener.class);
String containerBeanName = String.format("%s_%s", beanName, counter.incrementAndGet());
GenericApplicationContext genericApplicationContext = (GenericApplicationContext) context;
genericApplicationContext.registerBean(containerBeanName, DefaultMQPushConsumer.class,
() -> createRocketMQConsumer(containerBeanName, bean, annotation));
DefaultMQPushConsumer consumer = genericApplicationContext.getBean(containerBeanName, DefaultMQPushConsumer.class);
try {
consumer.start();
log.info("A consumer as {} init on namesrc {}", beanName, namesrvAddr);
} catch (MQClientException e) {
throw new RuntimeException("A consumer as " + beanName + " start fail, " + e.getMessage());
}
}
private DefaultMQPushConsumer createRocketMQConsumer(String containerBeanName, Object bean, RocketMQMessageListener annotation) {
String topic = annotation.topic();
String consumerGroup = annotation.consumerGroup();
Assert.hasText(topic, containerBeanName.substring(0,containerBeanName.indexOf("_")) + " topic 不允许为空");
Assert.hasText(consumerGroup, containerBeanName.substring(0,containerBeanName.indexOf("_")) + " consumerGroup 不允许为空");
String selectorExpression = annotation.selectorExpression();
ConsumeMode consumeMode = annotation.consumeMode();
MessageModel messageModel = annotation.messageModel();
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(consumerGroup);
consumer.setNamesrvAddr(namesrvAddr);
try {
consumer.subscribe(topic, selectorExpression);
switch (messageModel) {
case BROADCASTING:
consumer.setMessageModel(org.apache.rocketmq.common.protocol.heartbeat.MessageModel.BROADCASTING);
break;
case CLUSTERING:
consumer.setMessageModel(org.apache.rocketmq.common.protocol.heartbeat.MessageModel.CLUSTERING);
break;
default:
throw new IllegalArgumentException("Property 'messageModel' was wrong.");
}
RocketMQListener listener = (RocketMQListener) bean;
if (consumeMode == ConsumeMode.ORDERLY) {
// 顺序消费
consumer.registerMessageListener((MessageListenerOrderly) (msgs, context) -> {
for (MessageExt ext: msgs) {
log.info("Orderly message, {}", ext);
listener.onMessage(new String(ext.getBody(), StandardCharsets.UTF_8));
}
return ConsumeOrderlyStatus.SUCCESS;
});
} else {
// 并发
consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
for (MessageExt ext: msgs) {
log.info("Concurrently message, {}", ext);
listener.onMessage(new String(ext.getBody(), StandardCharsets.UTF_8));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
});
}
} catch (MQClientException e) {
throw new RuntimeException("A consumer as " + containerBeanName + " registerBean fail, " + e.getMessage());
}
consumerList.add(consumer);
return consumer;
}
}
package org.rocketmq.template;
import org.apache.rocketmq.client.producer.*;
import org.apache.rocketmq.common.message.Message;
import org.rocketmq.utils.MessagesSplitter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
* @author zd
* @date 2023/2/2 11:39
* @description 消息发送封装
* 方法含义:同步发送send, 异步发送sendAsync, 单向发送sendOneway
*/
public class RocketMQTemplate {
private static final Logger log = LoggerFactory.getLogger(RocketMQTemplate.class);
private DefaultMQProducer defaultMQProducer;
private TransactionMQProducer transactionMQProducer;
public void setDefaultMQProducer(DefaultMQProducer defaultMQProducer) {
this.defaultMQProducer = defaultMQProducer;
}
public void setTransactionMQProducer(TransactionMQProducer transactionMQProducer) {
this.transactionMQProducer = transactionMQProducer;
}
public SendResult send(String topic, String msg, long timeout) throws Exception {
return this.send(topic, "", msg, timeout);
}
public SendResult send(String topic, String tags, String msg, long timeout) throws Exception {
return this.send(topic, tags, "", msg, 0, timeout);
}
public SendResult send(String topic, String tags, String keys, String msg, int delayTimeLevel, long timeout) throws Exception {
return this.sendMsg(topic, tags, keys, msg, null, false, delayTimeLevel, timeout);
}
public void sendAsync(String topic, String msg, SendCallback sendCallback, long timeout) throws Exception {
this.sendAsync(topic, "", msg, sendCallback, timeout);
}
public void sendAsync(String topic, String tags, String msg, SendCallback sendCallback, long timeout) throws Exception {
this.sendAsync(topic, tags, "", msg, sendCallback, 0, timeout);
}
public void sendAsync(String topic, String tags, String keys, String msg, SendCallback sendCallback, int delayTimeLevel, long timeout) throws Exception {
this.sendMsg(topic, tags, keys, msg, sendCallback, false, delayTimeLevel, timeout);
}
public void sendOneway(String topic, String msg, long timeout) throws Exception {
this.sendOneway(topic, "", msg, timeout);
}
public void sendOneway(String topic, String tags, String msg, long timeout) throws Exception {
this.sendOneway(topic, tags, "", msg, 0, timeout);
}
public void sendOneway(String topic, String tags, String keys, String msg, int delayTimeLevel, long timeout) throws Exception {
this.sendMsg(topic, tags, keys, msg, null, true, delayTimeLevel, timeout);
}
public SendResult send(String topic, String tags, String msg, MessageQueueSelector selector, Object arg) throws Exception {
return this.sendMsg(topic, tags, "", msg, null, false, 0, 0, selector, arg);
}
/**
* 批量消息,注意最大4MB
*/
public void sendBatch(List<Message> msgs) throws Exception {
MessagesSplitter messagesSplitter = new MessagesSplitter(msgs);
while (messagesSplitter.hasNext()) {
List<Message> subMessageList = messagesSplitter.next();
SendResult sendResult = this.defaultMQProducer.send(subMessageList);
log.info("消息发送状态: {}, size,{}", sendResult, sendResult.getMsgId().split(",").length);
}
}
private Message createMessage(String topic, String tags, String keys, String msg, SendCallback sendCallback, boolean isOneway,
int delayTimeLevel, long timeout) {
Message message = new Message(topic, tags, keys, msg.getBytes(StandardCharsets.UTF_8));
message.setDelayTimeLevel(delayTimeLevel);
if (timeout > 0) {
message.setDeliverTimeMs(timeout);
}
return message;
}
/**
* 发送普通消息
*
* @param topic 主题
* @param tags 过滤标签Tag
* @param keys 索引Key列表
* @param sendCallback 异步回调
* @param isOneway 是否单向发送
* @param delayTimeLevel 延时消息等级,大于0才起作用,级别: 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
* @param timeout 定时时间戳,单位毫秒
*/
private SendResult sendMsg(String topic, String tags, String keys, String msg, SendCallback sendCallback, boolean isOneway,
int delayTimeLevel, long timeout) throws Exception {
Message message = createMessage(topic, tags, keys, msg, sendCallback, isOneway, delayTimeLevel, timeout);
log.info("监听到消息发送, topic={}, tags={}, keys={}, msg={}, isOneway={}, delayTimeLevel={}, timeout={}",
topic, tags, keys, msg, isOneway, delayTimeLevel, timeout);
if (isOneway) {
// 单向发送,由于在oneway方式发送消息时没有请求应答处理,如果出现消息发送失败,则会因为没有重试而导致数据丢失。若数据不可丢,建议选用可靠同步或可靠异步发送方式。
this.defaultMQProducer.sendOneway(message);
} else {
if (sendCallback == null) {
// 同步发送消息,只要不抛异常就是成功。
return this.defaultMQProducer.send(message);
} else {
// 异步发送
this.defaultMQProducer.send(message, sendCallback);
}
}
return null;
}
/**
* @param selector 消息队列选择器,根据业务唯一标识自定义队列选择算法
* @param arg 选择队列的业务标识
*/
private SendResult sendMsg(String topic, String tags, String keys, String msg, SendCallback sendCallback, boolean isOneway,
int delayTimeLevel, long timeout, MessageQueueSelector selector, Object arg) throws Exception {
Message message = createMessage(topic, tags, keys, msg, sendCallback, isOneway, delayTimeLevel, timeout);
log.info("监听到消息发送, message={}", message);
return this.defaultMQProducer.send(message, selector, arg);
}
/**
* 发送事务消息
*/
public TransactionSendResult sendTransactionMsg(Message message) throws Exception {
return this.transactionMQProducer.sendMessageInTransaction(message, null);
}
}
package org.rocketmq.config;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.exception.MQClientException;
import org.rocketmq.template.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.Assert;
/**
* @author zd
* @date 2023/2/1 16:34
* @description rocketmq配置
*/
@Slf4j
@Configuration
@EnableConfigurationProperties(RocketMQProperties.class)
@ConditionalOnProperty(prefix = "rocketmq", value = "name-server", matchIfMissing = true)
public class RocketMQConfig {
@Bean(name = "rocketMQProducer", initMethod = "initMQProducer", destroyMethod = "close")
public RocketMQProducer defaultMQProducer(RocketMQProperties properties) throws MQClientException {
RocketMQProperties.Producer producerProperties = properties.getProducer();
String nameServer = properties.getNameServer();
String group = producerProperties.getGroup();
Assert.hasText(nameServer, "[rocketmq.name-server] 不允许为空");
Assert.hasText(group, "[rocketmq.producer.group] 不允许为空");
// 创建消息生产者
RocketMQProducer producer = new RocketMQProducer();
producer.setNamesrvAddr(nameServer);
producer.setProduceGroup(group);
log.info("nameserver {} producer初始化", nameServer);
return producer;
}
@Bean
public RocketMQTemplate rocketMQTemplate(@Qualifier("rocketMQProducer") RocketMQProducer producer) {
RocketMQTemplate template = new RocketMQTemplate();
template.setDefaultMQProducer(producer.getDefaultMQProducer());
template.setTransactionMQProducer(producer.getTransactionMQProducer());
return template;
}
@Bean
public RocketMQConsumer rocketMQConsumer(RocketMQProperties properties) {
String nameServer = properties.getNameServer();
Assert.hasText(nameServer, "[rocketmq.name-server] 不允许为空");
RocketMQConsumer consumer = new RocketMQConsumer();
consumer.setNamesrvAddr(nameServer);
return consumer;
}
}
package org.rocketmq.utils;
import org.apache.rocketmq.common.message.Message;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* @Author: zd
* @Date: 2023-02-08 21:53
* @Description: 消息分隔器
*/
public class MessagesSplitter implements Iterator<List<Message>> {
private final int SIZE_LIMIT = 1024 * 1024 * 1;
private final List<Message> messages;
private int currIndex;
public MessagesSplitter(List<Message> messages) {
this.messages = messages;
}
@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 message = messages.get(nextIndex);
int tmpSize = message.getTopic().length() + message.getBody().length;
Map<String, String> properties = message.getProperties();
for (Map.Entry<String, String> entry : properties.entrySet()) {
tmpSize += entry.getKey().length() + entry.getValue().length();
}
//日志开销 20字节
tmpSize = tmpSize + 20;
if (tmpSize + totalSize > SIZE_LIMIT) {
break;
} else {
totalSize += tmpSize;
}
}
List<Message> subList = messages.subList(currIndex, nextIndex);
currIndex = nextIndex;
return subList;
}
}
源码及使用案例:
https://gitee.com/dalao708/Demo/tree/master/java/mq/rocketmq/rocketmq-demo
.