springboot下rocketmq-client消息接收发布示例代码

参考官方文档,大部分功能的示例代码都可以从这个地址找到

https://github.com/apache/rocketmq/blob/master/docs/cn/RocketMQ_Example.md

就是官网稍稍复杂些,并且是脱离springboot的,对任务繁重的开发们可能不太友好,而我的示例注释比较多,可以直接复制就用

消费者部分代码

MyConsumerConfig.java
package com.lbx.ms.mq.bill2crm;

import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

@Configuration
public class MyConsumerConfig {


    public final Logger log = LoggerFactory.getLogger(MyConsumerConfig.class);

    //消费组名称
    @Value("${yourCompany.rocketMq.groupName}")
    private String consumerGroup = null;

    //rockmq集群namesrver的地址
    @Value("${yourCompany.rocketMq.namesrvAddr}")
    private String namesrvAddr = null;

    //主题
    @Value("${yourCompany.rocketMq.topic}")
    private String topic = null;

    //tag,用于筛选主题下指定tag的信息
    @Value("${yourCompany.rocketMq.tags}")
    private String tags = null;

    //最大线程数
    @Value("${yourCompany.rocketMq.consumeThreadMax}")
    private Integer consumeThreadMax = null;

    //每次拉取消息最多拉取多少条
    @Value("${yourCompany.rocketMq.consumeMessageBatchMaxSize}")
    private Integer consumeMessageBatchMaxSize = null;



    @Bean("MyConsumer")
    public DefaultMQPushConsumer MyConsumer() throws Exception {
        DefaultMQPushConsumer consumer = getDefaultMQPushConsumer();
        consumer.start();
        log.info("Consumer started..............");
        return consumer;
    }

    /**
     * MQ消费者-配置封装
     *
     * @return
     * @throws Exception
     */
    public DefaultMQPushConsumer getDefaultMQPushConsumer() throws Exception {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(consumerGroup);
        consumer.setNamesrvAddr(namesrvAddr);
        consumer.subscribe(topic, StringUtils.isBlank(tags) ? null : tags);
        consumer.setConsumeMessageBatchMaxSize(consumeMessageBatchMaxSize);
        consumer.setConsumeThreadMax(consumeThreadMax);
        consumer.registerMessageListener(getMessageListenerConcurrently());
        //默认配置:CONSUME_FROM_LAST_OFFSET
        //消费者客户从以前停止的地方开始。如果它是一个新启动的消费者客户端,根据消费者群体的年龄,有两个,
        // 如果消费者组是最近创建的,因此订阅的最早消息尚未过期,这意味着消费者组代表最近启动的业务,则消费将从头开始;
        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
        //如果订阅的最早消息已过期,则消费将从最新消息开始,这意味着在启动时间戳之前生成的消息将被忽略
        return consumer;
    }

    /**
     * 消费者-消费逻辑
     *
     * @return
     * @throws Exception
     */
    //返回类型为MessageListenerConcurrently:用于并发消费
    //返回类型为MessageListenerOrderly: 用于按顺序接收异步传递的消息。一个队列,一个线程
    public MessageListenerConcurrently getMessageListenerConcurrently() {
        return (List<MessageExt> msgs, ConsumeConcurrentlyContext context) -> {
            for (MessageExt msg : msgs) {
                String currentMsgBody = new String(msg.getBody());
                currentMsgBody = currentMsgBody.replaceAll("\n", "").replaceAll("\t", "");
                log.info("消费者:接收到mq消息:msg.getBody():{} ; msg.getMsgId():{}", currentMsgBody, msg.getMsgId());
            }
            //如果返回这个标识,接下来的一段时间会有消息重复发送过来,默认发16次,并且重发间隔会越来越长
            //return ConsumeConcurrentlyStatus.RECONSUME_LATER;
            //返回成功的标识
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        };
    }
}





/**
 *  重复消费场景:
 *  1.消息队列服务器发信息时遇到网络问题,发送中断,于是重新发送
 *    解决办法:(1)由于同一条消息一般只会出现在一个消费者上,为单线程,业务上判断是否已经消费过,消费过就无需再次消费
 *              (2)对key增加分布式锁,锁内判断是否重复消费
 *              (3)消费端改成幂等代码
 *
 *  2.消息队列服务器没有收到ack信息,或者收到消费失败的ack标识,于是重新发送
 *                (1)解决代码报错问题
 *
 *
 *  消息丢失场景:
 *  1.异步刷盘导致消息丢失
 *  2.自动ack导致消息丢失
 *
 *
 *
 *  消息顺序消费的方法
 *  方法1.将所有消息放入同一个分区
 *  方法2.将消息分类,需要顺序消费的消息放入同一个分区,可实现有序。不需要顺序消费的消息放入不同分区,提升整体消息消费速度
 *
 *
 *
 */





application.yml

spring:
  application:
    name: rocketmqDemo
  profiles:
    active: dev

yourCompany:
  rocketMq:
    namesrvAddr: 127.0.0.1:9876
    groupName: testtopicConcurrencyGroup_dev
    tags:
    topic: testtopicConcurrency
    consumeThreadMax: 20
    consumeMessageBatchMaxSize: 1


server:
  port: 8067


logging:
  level:
    com.lbx.ms.mq: info

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>



    <groupId>com.lbx.ms.realtime</groupId>
    <artifactId>rocketmqDemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-client</artifactId>
            <version>4.3.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

</project>

启动类

Application.java
package com.lbx.ms.mq.bill2crm;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

生产者代码

MyProducerConfig.java
package com.lbx.ms.mq.bill2crm;

import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class MyProducerConfig {

    public final Logger log = LoggerFactory.getLogger(MyProducerConfig.class);

    //组名称
    @Value("${yourCompany.rocketMq.groupName}")
    private String groupName = null;

    //rockmq集群namesrver的地址
    @Value("${yourCompany.rocketMq.namesrvAddr}")
    private String namesrvAddr = null;


    @Bean("MyProducer")
    public DefaultMQProducer MyProducer() throws MQClientException {
        // 实例化消息生产者Producer
        //生产者组名称在概念上聚合了完全相同角色的所有生产者实例,这在涉及事务消息时尤为重要
        //涉及事务消息时,需要注意的是事务消息的生产组名称 ProducerGroupName不能随意设置。事务消息有回查机制,回查时Broker端如果发现原始生产者已经崩溃,则会联系同一生产者组的其他生产者实例回查本地事务执行情况以Commit或Rollback半事务消息。
        //对于非事务性消息,只要生产者组名称在每个进程中是唯一的,就无关紧要,在4.x版本的rocketmq客户端中,相同的producerGroupname会引起报错
        //Apache RocketMQ 服务端5.x版本开始,生产者是匿名的,无需管理生产者分组
        DefaultMQProducer producer = new DefaultMQProducer("producer" + System.currentTimeMillis() / 1000);
        // 设置NameServer的地址
        producer.setNamesrvAddr(namesrvAddr);
        // 启动Producer实例
        producer.start();
        log.info("producer start....");
        return producer;
    }


}









测试类代码

DemoController.java
package com.lbx.ms.mq.bill2crm;

import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 发送消息测试类
 */
@RestController
public class DemoController {


    public final Logger log = LoggerFactory.getLogger(DemoController.class);

    @Autowired
    DefaultMQProducer myProducer;

    //消费组名称
    @Value("${yourCompany.rocketMq.topic}")
    private String topic = null;

    /**
     * 发送消息
     */
    @GetMapping("/send")
    public SendResult send() throws Exception {
        Message msg = new Message(topic, "你好,RocketMQ ".getBytes(RemotingHelper.DEFAULT_CHARSET));
        log.info("即将发送消息{}", msg);
        SendResult sendResult = myProducer.send(msg);
        log.info("{}", sendResult);
        return sendResult;
    }

}

验证下代码能否正常运行

启动rocketmq服务器,启动该springboot项目

在浏览器发送请求

http://localhost:8067/send

得到如下结果

控制台打印如下

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值