简述

本文主要介绍Springboot项目如何集成阿里RocketMQ服务以及基本使用

消息队列作为高并发系统的核心组件之一,能够帮助业务系统解构提升开发效率和系统稳定性。

1、注册阿里云账户,购买RocketMQ服务

1、购买RocketMQ服务,创建实例配置
2、在实例中创建消息主题Topic
3、创建消息消费者组Group
注意规则:
一个 Group ID 代表一个 Consumer 实例群组。同一个消费者 Group ID 下所有的 Consumer 实例必须保证订阅的 Topic 一致,
并且也必须保证订阅 Topic 时设置的过滤规则(Tag)一致

2、配置Maven依赖
<!-- RocketMQ依赖 -->
<dependency>
    <groupId>com.aliyun.openservices</groupId>
    <artifactId>ons-client</artifactId>
    <version>1.8.4.Final</version>
</dependency>
3、Application.yml参数配置
## 阿里RocketMQ配置
rocketmq:
  ## 连接点地址 参考控制台实例详情
  name-server: http://MQ_INST_666666666666666666666
  ## 主题
  topic: test_topic
  ## 过滤标签
  tag: test_tag
  producer:
    ## 订阅者组
    group:test_group
  consumer:
    ## 阿里云密码
    access-key: xxxxxxxxxxxxxxx
    secret-key: xxxxxxxxxxxxxxx
    # 消费者线程
    thread-num: 20
4、创建消息的生产者

消息的生产者主要为产生消息对象,他们向消息队列中发送消息。

@Configuration
public class ProducerClient {

    @Value("${rocketmq.name-server}")
    private String serverAddress;

    @Value("${rocketmq.producer.group}")
    private String group;

    @Value("${rocketmq.consumer.access-key}")
    private String accessKey;

    @Value("${rocketmq.consumer.secret-key}")
    private String secretKey;

    @Bean(initMethod = "start", destroyMethod = "shutdown")
    public ProducerBean buildProducer() {
        ProducerBean producer = new ProducerBean();
        //配置文件
        Properties properties = new Properties();
        // AccessKey 阿里云身份验证,在阿里云服务器管理控制台创建
        properties.setProperty(PropertyKeyConst.AccessKey, accessKey);
        // SecretKey 阿里云身份验证,在阿里云服务器管理控制台创建
        properties.setProperty(PropertyKeyConst.SecretKey, secretKey);
        // 设置 TCP 接入域名,进入控制台的实例管理页面的“获取接入点信息”区域查看
        properties.setProperty(PropertyKeyConst.NAMESRV_ADDR, serverAddress);
        //设置发送超时时间,单位毫秒
        properties.setProperty(PropertyKeyConst.SendMsgTimeoutMillis, "3000");
        //设置组id
        properties.setProperty(PropertyKeyConst.GROUP_ID, group);
        producer.setProperties(properties);
        return producer;
    }
}
5、生产者消息-异步发送结果处理类

消息的异步发送为主要的消息发送方式,该方式需要进行处理发送结果。

@Slf4j
public class RocketSendAsyncMessage implements SendCallback {

    @Override
    public void onSuccess(SendResult sendResult) {
        log.info(">>>>> 【生产者】系统时间:[{}]异步发送消息MsgID=[{}]成功!", LocalDateTime.now(),sendResult.getMessageId());
    }

    @Override
    public void onException(OnExceptionContext onExceptionContext) {
        log.info(">>>>> 【生产者】系统时间:[{}]异步发送消息MsgID=[{}]失败!", LocalDateTime.now(),onExceptionContext.getMessageId());
    }
}
6、生产者消息工具类

生产者可以生成不同的消息,根据消息类型的不同,发送方式也不一样。

@Slf4j
@Component
public class RocketMQUtil {

    @Autowired
    ProducerBean producer;

    @Value("${rocketmq.topic}")
    private String topic;

    @Value("${rocketmq.tag}")
    private String tag;
    /**
     * 发送普通消息
     * @param content 消息内容
     * */
    public void sendMessage(String content){
        Message msg = new Message();
        //设置主题和标签
        msg.setTopic(topic);
        msg.setTag(tag);
        msg.setBody(content.getBytes());
        try {
            SendResult sendResult = producer.send(msg);
            // 同步发送消息,只要不抛异常就是成功
            if (sendResult != null) {
                log.info(">>>>> 【生产者】系统时间:[{}]同步发送消息成功, MsgID=[{}]", LocalDateTime.now(),sendResult.getMessageId());
            }
        }catch (Exception e) {
            // 消息发送失败
            log.info(">>>>> 【生产者】系统时间:[{}]同步发送消息成功, Topic=[{}]", LocalDateTime.now(),msg.getTopic());
            // 需要重试或者持久化数据进行补偿处理
            e.printStackTrace();
        }
    }

    /**
     * 发送异步消息消息
     * @param content 消息内容
     * */
    public void sendAsyncMessage(String content){
        Message msg = new Message();
        //设置主题和标签
        msg.setTopic(topic);
        msg.setTag(tag);
        msg.setBody(content.getBytes());
        producer.sendAsync(msg,new RocketSendAsyncMessage());
    }

    /**
     * 发送oneWay消息消息
     * @param content 消息内容
     * */
    public void sendOneWayMessage(String content){
        Message msg = new Message();
        //设置主题和标签
        msg.setTopic(topic);
        msg.setTag(tag);
        msg.setBody(content.getBytes());
        producer.sendOneway(msg);
    }
}
7、消费者客户端

消费者客户端主要用来进行消息的消费操作,即处理订阅的消息队列中的消息。

@Configuration
public class ConsumerClient {

    @Value("${rocketmq.name-server}")
    private String serverAddress;

    @Value("${rocketmq.topic}")
    private String topic;

    @Value("${rocketmq.tag}")
    private String tag;

    @Value("${rocketmq.producer.group}")
    private String group;

    @Value("${rocketmq.consumer.access-key}")
    private String accessKey;

    @Value("${rocketmq.consumer.secret-key}")
    private String secretKey;

    @Value("${rocketmq.consumer.thread-num}")
    private String threadNum;

    @Autowired
    private MyRocketMessageListener messageListener;

    @Bean(initMethod = "start", destroyMethod = "shutdown")
    public ConsumerBean buildConsumer() {

        //消费者对象bean
        ConsumerBean consumerBean = new ConsumerBean();
        //配置文件
        Properties properties = new Properties();
        //设置消费者信息
        properties.setProperty(PropertyKeyConst.AccessKey, accessKey);
        properties.setProperty(PropertyKeyConst.SecretKey, secretKey);
        properties.setProperty(PropertyKeyConst.NAMESRV_ADDR, serverAddress);
        //设置组id
        properties.setProperty(PropertyKeyConst.GROUP_ID, group);
        //将消费者线程数固定为20个 20为默认值
        properties.setProperty(PropertyKeyConst.ConsumeThreadNums, threadNum);
        consumerBean.setProperties(properties);

        //配置订阅关系
        Map<Subscription, MessageListener> subscriptionTable = new HashMap<>();
        //当前为订阅一个主题配置(订阅多个topic一样设置)
        Subscription subscription = new Subscription();
        subscription.setTopic(topic);
        subscription.setExpression(tag);
        subscriptionTable.put(subscription, messageListener);
        consumerBean.setSubscriptionTable(subscriptionTable);
        return consumerBean;
    }
}
8、消费者客户端消息监听器

消费者客户端通过监听器来接收队列发送的消息,再监听器中可以添加消息的简单处理逻辑。

@Slf4j
@Component
public class MyRocketMessageListener implements MessageListener {

    @Autowired
    private RocketMQService rocketMQService;

    @Override
    public Action consume(Message message, ConsumeContext context) {

        // 业务处理逻辑
        log.info(">>>>> 【消费者】系统时间:[{}]接收消息MsgId=[{}],消息内容:{}",LocalDateTime.now(),message.getMsgID(),new String(message.getBody(), StandardCharsets.UTF_8));
        try {
            //添加消息到数据库
            rocketMQService.addMessage(message);
            return Action.CommitMessage;
        } catch (Exception e) {
            //消费失败
            log.error(">>>>> 【消费者】系统时间:[{}]处理消息MsgId=[{}], 当前消费失败, 开始重试......!",LocalDateTime.now(),message.getMsgID());
            return Action.ReconsumeLater;
        }
    }
}