RocketMQ5.0

官网
参考:
https://rocketmq.apache.org/zh/docs/quickStart/02quickstart
https://rocketmq.apache.org/zh/docs/deploymentOperations/15deploy

1、部署

  • 可以使用源码包安装或者二进制包安装,以下只是单台机器的部署做测试,做集群可以参考官网文档。
    RocketMQ5.0_第1张图片

  • linux基本环境

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
  • 相关示例截图
    在这里插入图片描述
    RocketMQ5.0_第2张图片

RocketMQ5.0_第3张图片
RocketMQ5.0_第4张图片
在这里插入图片描述
RocketMQ5.0_第5张图片
RocketMQ5.0_第6张图片

  • RocketMQ Dashboard安装参考链接:https://rocketmq.apache.org/zh/docs/deploymentOperations/18Dashboard
    注意:如果主机访问不了虚拟机的RocketMQ Dashboard,可以检查虚拟机8080、8081、9876,10911,11011 端口端口是否开放
    在这里插入图片描述

2、springboot整合封装rocketmq-client

  • Apache RocketMQ 服务端5.x版本开始,生产者是匿名的,无需管理生产者分组(ProducerGroup);对于历史版本服务端3.x和4.x版本,已经使用的生产者分组可以废弃无需再设置,且不会对当前业务产生影响。
  • 参考:
    https://github.com/apache/rocketmq-spring/tree/master
    https://blog.csdn.net/alitech2017/article/details/113933609
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
  • 引入原生rocketmq-client sdk依赖
        <!-- 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);
    }

}

  • 最后注入spring
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

.

你可能感兴趣的:(中间件,java,中间件)