spring boot 整合rocket mq

107 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

上一篇中我们成功的搭建了rocketmq,并且在工程中引入了rocketmq的maven依赖。也通过测试同步消息,验证了我们所安装的rocketmq的可行性。在开发中我们通常会使用spring boot框架,所以我们需要将两者结合起来进行整合。

首先我们需要在spring boot的yml文件中进行配置。比较常用的配置是下面这些。

server:
  port: 8081
spring:
  application:
    name: rocket-mq
rocketmq:
  name-server: 127.0.0.1:9876
  producer:
    #生产者组
    group: self-producer-group
  consumer:
    group: self-consumer-group

这里声明了我们要使用的rocketmq的服务地址,然后对生产者和消费者分别定义了他们的组。我结合文档上的定义就是,我们的程序中你可能会创建多个生产者或消费者,当然也可能你使用了集群那么对于我们的rocketmq来说,你也是创建了多个生产者或消费者。这些生产者投递到同一个broker或者,消费者们监听了同一个主题。那么为了便于统一管理这些实列,以及消费者的负载均衡策略,需要将它们进行分组。

首先我们创建一个消息生产者。

String topic = "spring-topic";
Message msg = new Message(topic,"tom", message.getBytes());
rocketMQTemplate.asyncSend(topic, msg, new SendCallback() {
    @Override
    public void onSuccess(SendResult sendResult) {
        log.info("{}",sendResult.toString());
    }

    @Override
    public void onException(Throwable throwable) {
        log.error(throwable.getMessage());
    }
});

这里我们使用异步消息,也就是不会造成程序的阻塞,执行投递消息之后程序可以继续执行后面的代码,等到投递的结果响应了,那么会回调到我们的onSuccess或onException方法上。这里使用了rocketMQTemplate,这个已经为我们封装了许多有用的方法,可以直接使用。这里我们选择在回调中判断消息是否成功投递到了rocketmq中。

然后我们创建一个消费者

@Slf4j
@Service
@RocketMQMessageListener(topic = "spring-topic",selectorExpression = "tom",consumerGroup = "self-consumer")
public class MessageConsumer implements RocketMQListener<String> {


    @Override
    public void onMessage(String s) {
        log.info(s);
    }
}

它需要和生产者订阅一样的主题,同时由于我们在发送消息的时候,已经声明了tag,tag是用来过滤部分消息或者说,只接受部分消息的一个逻辑标志。例如我们这里只接受该spring-topic主题下标签为tom的消息,也就是在这个主题下的消息,如果你的标签不是tom那么该消费者则不会来消费你。

分别启动生产者和消费者的服务,然后投递一条消息。

2022-04-04 20:03:24.042  INFO 12496 --- [ublicExecutor_1] c.z.s.service.impl.MessageServiceImpl    : SendResult [sendStatus=SEND_OK, msgId=7F00000130D018B4AAC213C0D2EA0000, offsetMsgId=792B291300002A9F000000000004A658, messageQueue=MessageQueue [topic=spring-topic, brokerName=broker-a, queueId=1], queueOffset=2]
2022-04-04 21:09:21.266  INFO 12496 --- [ublicExecutor_4] c.z.s.consumer.MessageConsumer           : {"topic":"spring-topic","flag":0,"properties":{"WAIT":"true","TAGS":"tom"},"body":"aGVsbG8=","transactionId":null,"keys":null,"tags":"tom","waitStoreMsgOK":true,"delayTimeLevel":0,"buyerId":null}

可以看到生产者和消费者都输出了正确的日志。我们再尝试下延时消息,这也是我们平时使用非常多的一个功能,我们需要修改下我们的生产者。

String topic = "spring-topic";
org.springframework.messaging.Message<String> stringMessage = MessageBuilder.withPayload(message).build();
rocketMQTemplate.asyncSend(topic+":tom", stringMessage, new SendCallback() {
    @Override
    public void onSuccess(SendResult sendResult) {
        log.info("{}",sendResult.toString());
    }

    @Override
    public void onException(Throwable throwable) {
        log.error(throwable.getMessage());
    }
},3000,3);
log.info(">>>>>>>>>>"+System.currentTimeMillis());

这里我们使用了spring的Message,将主题和标签用冒号拼接来指定消息投递到何处。后面两个时间参数,一个是投递的超时时间,一个是延时的时间等级(开源版的rocketmq只提供了时间等级的延时,也就是只能使用它定义的几个时间,不能自定义延时13分钟或1小时12分钟),这里3在默认的时间等级之中表示延时10s。

然后重启生产者服务,投递一条消息,通过日志可以看到

2022-04-04 21:36:12.494  INFO 732 --- [nio-8081-exec-1] c.z.s.service.impl.MessageServiceImpl    : >>>>>>>>>>1649079372494
2022-04-04 21:36:13.071  INFO 732 --- [ublicExecutor_1] c.z.s.service.impl.MessageServiceImpl    : SendResult [sendStatus=SEND_OK, msgId=7F00000102DC18B4AAC21415CCEE0000, offsetMsgId=792B291300002A9F000000000004A82B, messageQueue=MessageQueue [topic=spring-topic, brokerName=broker-a, queueId=0], queueOffset=5]
2022-04-04 21:36:23.067  INFO 732 --- [MessageThread_1] c.z.s.consumer.MessageConsumer           : >>>>>>>>>hello

在10s后接受到了消息,注意10s的延时,是指消息抵达rocketmq之后会被暂存10s,然后被投递出去。而不是从生产者生产消息开始算起。到此说明延时消息已经成功实现了。