Spring整合RocketMQ(一)

Spring整合RocketMQ

首先创建两个maven工程,分别是rocketmq-study-consumerrocketmq-study-producer,都添加以下依赖

<dependencies>
    <!--rocketmq包-->
    <dependency>
        <groupId>org.apache.rocketmq</groupId>
        <artifactId>rocketmq-client</artifactId>
        <version>4.8.0</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.10</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <version>2.2.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <version>2.2.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.2.2.RELEASE</version>
    </dependency>
</dependencies>

生产者

主启动类

package com.zhima;

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

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

yml文件

rocketmq:
  producer:
    # 所在生产组的组名
    group-name: rocketmq-producer-group1
    # 是否启动生产者
    is-on-off: on
    # mq的namesrv的地址,多个地址用;分割
    namesrv-addr: localhost:9876
    # 消息的最大长度,单位字节,默认4M
    max-message-size: 4096
    # 失败重试次数
    retry-times-when-send-failed: 2 
    # 发送消息超时时间
    send-msg-timeout: 3000

生产者属性类

package com.zhima.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Data
@ConfigurationProperties(prefix = "rocketmq.producer")
public class RocketMqProducerProperties {
    private String isOnOff;
    private String groupName;
    private String namesrvAddr;
    private Integer maxMessageSize;
    private Integer sendMsgTimeout;
    private Integer retryTimesWhenSendFailed;
}

生产者配置类

package com.zhima.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

@Slf4j
@Configuration
@EnableConfigurationProperties(RocketMqProducerProperties.class)
public class RocketMqProducerConfiguration {

    @Resource
    private RocketMqProducerProperties rocketMqProducerProperties;

    @Bean
    public DefaultMQProducer getRocketMQProducer() {
        if (StringUtils.isEmpty(rocketMqProducerProperties.getGroupName())) {
            throw new RuntimeException("rocketMq producer groupName is blank");
        }
        if (StringUtils.isEmpty(rocketMqProducerProperties.getNamesrvAddr())) {
            throw new RuntimeException("rocketMq producer nameServerAddr is blank");
        }
        DefaultMQProducer producer = new DefaultMQProducer(rocketMqProducerProperties.getGroupName());
        producer.setNamesrvAddr(rocketMqProducerProperties.getNamesrvAddr());
        // 如果需要同一个jvm中不同的producer往不同的mq集群发送消息,需要设置不同的instanceName
        // producer.setInstanceName("producer1");
        producer.setMaxMessageSize(rocketMqProducerProperties.getMaxMessageSize());
        producer.setSendMsgTimeout(rocketMqProducerProperties.getSendMsgTimeout());
        producer.setRetryTimesWhenSendFailed(rocketMqProducerProperties.getRetryTimesWhenSendFailed());
        try {
            producer.start();
            log.info("producer starts successfully !, groupName: {} ,namesrvAddr:{}", rocketMqProducerProperties.getGroupName(), rocketMqProducerProperties.getNamesrvAddr());
        } catch (MQClientException e) {
            log.error("producer starts failure, reason: {}", e.getMessage());
            throw new RuntimeException(e);
        }
        return producer;
    }
}

生产者控制器

package com.zhima.controller;

import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
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.exception.RemotingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/producer")
public class RocketMqProducerController {
    @Autowired
    private DefaultMQProducer defaultMQProducer;

    @PostMapping("/send/{topic}/{tags}/{message}")
    public SendResult send(
            @PathVariable("message") String message,
            @PathVariable("topic") String topic,
            @PathVariable("tags") String tags) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        System.out.printf("开始发送消息: %s%n", message);
        return defaultMQProducer.send(new Message(topic, tags, message.getBytes()));
    }
}

测试

在这里插入图片描述

消费者

Consumer 组名,多个Consumer如果属于一个应用,订阅同样的消息,且消费逻辑一致,则应该将它们归为同一组

如果一个Consumer Group内的两个Consumer订阅不相同的Topic,可能会导致各Consumer只消费到一部分Topic

相关问题的博客:https://blog.csdn.net/qq_41377914/article/details/85092816

不同的consumerGroup名称属于不同的消费者集群,不同的消费者集群订阅了同一个topic,那么消息会广播给两个消费者集群

消费者集群中的消费者是以广播模式收到消息,还是通过负载均衡轮训收到消息是由消费端订阅方式messageModel决定的

默认消费模式时负载均衡,并不是广播模式,如果需要开启广播模式需要设置如下代码即可

consumer.setMessageModel(MessageModel.BROADCASTING);

主启动类

package com.zhima;

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

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

yml配置文件

server:
  port: 8081

rocketmq:
  consumer:
    # 所在消费组的组名
    group-name: rocketmq-consumer-group1
    # 是否启动消费者
    is-on-off: on
    # mq的namesrv的地址,多个地址用;分割
    namesrv-addr: localhost:9876
    # 最小消费线程数
    consume-thread-min: 20
    # 最大消费线程数
    consume-thread-max: 64
    # 订阅的主题和tags
    # 格式:topicName~tag1||tag2||tag3;topicName2~*
    # 订阅topicName下的tag1、tag2、tag3主题和topicName2下的所有tags
    topics: test_topic~*
    # 一次消费的最大消息条数,默认1条
    consume-message-batch-max-size: 1

消费者属性类

package com.zhima.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ConfigurationProperties(prefix = "rocketmq.consumer")
public class RocketMqConsumerProperties {
    private String isOnOff;
    private String groupName;
    private String namesrvAddr;
    private String topics;
    private Integer consumeThreadMin = 16;
    private Integer consumeThreadMax = 64;
    private Integer consumeMessageBatchMaxSize = 1;
}

消费者本尊

package com.zhima.consumer;

import lombok.extern.slf4j.Slf4j;
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.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.nio.charset.StandardCharsets;
import java.util.List;


@Component
@Slf4j
public class RocketMqMessageListener implements MessageListenerConcurrently {

    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> messageExts, ConsumeConcurrentlyContext context) {
        if (CollectionUtils.isEmpty(messageExts)) {
            log.info("消息为空");
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        }
        for (MessageExt messageExt : messageExts) {
            log.info("接受到的消息为:{}", messageExt.toString());
            // 消费此条消息
            String message = new String(messageExt.getBody(), StandardCharsets.UTF_8);
            log.info("消费者收到消息:{}", message);
        }
        // 如果没有return success ,broker会重复下发该消息,并且记录重试次数
        // consumer会重复消费该消息,直到return success
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
}

消费者配置类

package com.zhima.config;

import com.zhima.processor.RocketMqConsumer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

@Slf4j
@Configuration
@EnableConfigurationProperties(RocketMqConsumerProperties.class)
public class RocketMqConsumerConfiguration {
    @Resource
    private RocketMqConsumerProperties RocketMqConsumerProperties;

    @Resource
    private RocketMqConsumer rocketMqConsumer;

    @Bean
    public DefaultMQPushConsumer getRocketMQConsumer() {
        if (StringUtils.isEmpty(RocketMqConsumerProperties.getGroupName())) {
            throw new RuntimeException("groupName is null !");
        }
        if (StringUtils.isEmpty(RocketMqConsumerProperties.getNamesrvAddr())) {
            throw new RuntimeException("namesrvAddr is null !");
        }
        if (StringUtils.isEmpty(RocketMqConsumerProperties.getTopics())) {
            throw new RuntimeException("topics is null !");
        }
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(RocketMqConsumerProperties.getGroupName());
        consumer.setNamesrvAddr(RocketMqConsumerProperties.getNamesrvAddr());
        consumer.setConsumeThreadMin(RocketMqConsumerProperties.getConsumeThreadMin());
        consumer.setConsumeThreadMax(RocketMqConsumerProperties.getConsumeThreadMax());
        // 注册消费消息的类
        consumer.registerMessageListener(rocketMqConsumer);
        //设置Consumer第一次启动是从队列头部开始消费还是队列尾部开始消费
        //如果非第一次启动,那么按照上次消费的位置继续消费
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
        // 设置消费模型,集群还是广播,默认为集群
        consumer.setMessageModel(MessageModel.BROADCASTING);
        // 设置一次消费消息的条数,默认为1条
        consumer.setConsumeMessageBatchMaxSize(RocketMqConsumerProperties.getConsumeMessageBatchMaxSize());
        try {
            // 设置该消费者订阅的主题和tag
            String[] topicTagsArr = RocketMqConsumerProperties.getTopics().split(";");
            for (String topicTags : topicTagsArr) {
                String[] topicTag = topicTags.split("~");
                consumer.subscribe(topicTag[0], topicTag[1]);
            }
            consumer.start();
            log.info("consumer start successfully, groupName:{},topics:{},namesrvAddr:{}", RocketMqConsumerProperties.getGroupName(),
                    RocketMqConsumerProperties.getTopics(), RocketMqConsumerProperties.getNamesrvAddr());
        } catch (MQClientException e) {
            log.error("consumer starts failure, groupName:{},topics:{},namesrvAddr:{}", RocketMqConsumerProperties.getGroupName(),
                    RocketMqConsumerProperties.getTopics(), RocketMqConsumerProperties.getNamesrvAddr(), e);
            throw new RuntimeException(e);
        }
        return consumer;
    }
}

测试

在RocketMqMessageListener中的consumeMessage方法的第一行打上断点

然后发送一条消息

在这里插入图片描述

查看控制台

在这里插入图片描述

在这里插入图片描述

初始化参数介绍

生产者

参数名参数说明
producerGroup消息生产组组名,一个应用的消息生产者应当归为一个生产者组
nameserAddr生产者地址
sendMsgTimeOut消息发送的超时时间
maxMessageSize消息最大大小,默认4M
retryTimesWhenSendFailed失败重试次数,默认2次
executorService事务消息处理线程池
transactionListener事务消息监听器

消费者

参数名含义
consumberGroup消费组名,一个应用的消费者都在一个消费组里面
nameserAddr消费者地址
consumeThreadMin消费者最小线程数
consumeThreadMax消费者最大线程数
consumeMessageBatchMaxSize并发消费数量,默认是1
subscribe消费者订阅主题信息
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芝麻\n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值