一起养成写作习惯!这是我参与「掘金日新计划 · 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,然后被投递出去。而不是从生产者生产消息开始算起。到此说明延时消息已经成功实现了。