- 前言
SpringBoot 是目前Java开发中的主流框架,RocketMQ 也是MQ里的佼佼者,这里做一个Sptring Boot 项目 整合集成 RocketMQ 的 Demo.
- 环境准备
SpringBoot 项目
RocketMq(安装流程 docker安装方式 https://my.oschina.net/u/4213839/blog/5064591 , 普通安装 https://my.oschina.net/u/4213839/blog/4965230 )
- Coding
引入 RocketMq 的依赖
<!-- RocketMQ -->
<dependency>
<groupId>com.alibaba.rocketmq</groupId>
<artifactId>rocketmq-all</artifactId>
<version>3.2.6</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.alibaba.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>3.2.6</version>
</dependency>
首先定义一个这个Demo相关的常量类
package com.lsz.test.recketmq;
/**
* 相关常量类
*
* @author lishuzhen
* @date 2021/5/31 22:53
*/
public class MqConstant {
public static final String NAME_SRV_ADDR = "192.168.109.128:9876";
public static final String TEST_TOPIC = "TEST_TOPIC";
public static final String CONSUMER_GROUP_1 = "CONSUMER_GROUP_1";
public static final String PRODUCER_GROUP_1 = "PRODUCER_GROUP_1";
}
编写 消息的生产者
package com.lsz.test.recketmq;
import com.alibaba.rocketmq.client.exception.MQClientException;
import com.alibaba.rocketmq.client.producer.DefaultMQProducer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 消息生产者
*
* @author lishuzhen
* @date 2021/5/31 21:54
*/
public class RocketMqProducer {
private final Logger logger = LoggerFactory.getLogger(RocketMqProducer.class);
private DefaultMQProducer defaultMQProducer;
public void init() throws MQClientException {
logger.info("RocketMqProducer initialize!");
// 初始化
defaultMQProducer = new DefaultMQProducer(MqConstant.PRODUCER_GROUP_1);
defaultMQProducer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
defaultMQProducer.setInstanceName(String.valueOf(System.currentTimeMillis()));
defaultMQProducer.start();
logger.info("RocketMqProducer start success!");
}
public void destroy() {
defaultMQProducer.shutdown();
}
public DefaultMQProducer getDefaultMQProducer() {
return defaultMQProducer;
}
}
编写 消息的消费者
package com.lsz.test.recketmq;
import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import com.alibaba.rocketmq.common.consumer.ConsumeFromWhere;
import com.alibaba.rocketmq.common.message.Message;
import com.alibaba.rocketmq.common.message.MessageExt;
import com.lsz.common.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* 消息消费者
*
* @author lishuzhen
* @date 2021/5/31 22:58
*/
public class PushConsumer {
private final Logger logger = LoggerFactory.getLogger(PushConsumer.class);
private String myName;
public PushConsumer(String myName) {
this.myName = myName;
}
public void init() {
logger.info("consumer running ... ");
DefaultMQPushConsumer consumer =
new DefaultMQPushConsumer(MqConstant.CONSUMER_GROUP_1);
consumer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
try {
// 订阅话题 并指定 tag
consumer.subscribe(MqConstant.TEST_TOPIC, "tag1 || tag2");
consumer.setConsumeFromWhere(
ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
consumer.registerMessageListener(
new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(
List<MessageExt> list,
ConsumeConcurrentlyContext Context) {
Message msg = list.get(0);
logger.info("mq {} time {}, 消息{}, 消息内容 = {}",
myName, DateUtils.dateTimeNow(), msg, new String(msg.getBody()));
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
}
);
consumer.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
定义一个生成bean的工厂类,只是为了做demo,初始化bean使用。
package com.kindergarten.test.recketmq;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* MQ 相关配置类
*
* @author lishuzhen
* @date 2021/5/31 22:55
*/
@Configuration
public class MqBeanFactory {
@Bean(initMethod = "init", destroyMethod = "destroy")
public RocketMqProducer createRocketMqProducer() {
return new RocketMqProducer();
}
@Bean(name = "Consumer1", initMethod = "init")
public PushConsumer createPushConsumer1() {
return new PushConsumer("Consumer1");
}
@Bean(name = "Consumer2", initMethod = "init")
public PushConsumer createPushConsumer2() {
return new PushConsumer("Consumer2");
}
}
最后编写一个测试接口
package com.lsz.test.recketmq;
import com.alibaba.rocketmq.client.exception.MQBrokerException;
import com.alibaba.rocketmq.client.exception.MQClientException;
import com.alibaba.rocketmq.client.producer.SendResult;
import com.alibaba.rocketmq.client.producer.SendStatus;
import com.alibaba.rocketmq.common.message.Message;
import com.alibaba.rocketmq.remoting.exception.RemotingException;
import com.lsz.common.result.ResultVO;
import com.lsz.common.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author lishuzhen
* @date 2021/5/31 22:56
*/
@RestController
@RequestMapping("api/mq")
public class MqController {
private final Logger logger = LoggerFactory.getLogger(MqController.class);
@Autowired
private RocketMqProducer rocketMqProducer;
/**
* 发送消息
*
* @param str
* @return
*/
@GetMapping("sendMsg/{tags}/{str}/{count}")
public ResultVO sendMsg(@PathVariable String str, @PathVariable String tags, @PathVariable Long count) {
Long successCount = 0L;
try {
for (Long i = 0L; i < count; i++) {
Message msg = new Message(MqConstant.TEST_TOPIC,
tags,
"HELLO_" + System.currentTimeMillis(),
(str + i).getBytes());
logger.info("mq producer time {}, 消息{}, 消息内容 = {}",
DateUtils.dateTimeNow(), msg, new String(msg.getBody()));
SendResult result = rocketMqProducer.getDefaultMQProducer().send(msg);
logger.info("mq producer 回调 time {}, result= {} ",
DateUtils.dateTimeNow(), result);
if (SendStatus.SEND_OK.equals(result.getSendStatus())) {
successCount++;
}
}
} catch (MQClientException e) {
e.printStackTrace();
} catch (RemotingException e) {
e.printStackTrace();
} catch (MQBrokerException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return ResultVO.success(successCount);
}
}
使用PostMan 调用接口
查看日志
23:09:37.517 [http-nio-8080-exec-5] INFO c.k.t.r.MqController - [sendMsg,47] - mq producer time 20210531230937, 消息Message [topic=TEST_TOPIC, flag=0, properties={KEYS=HELLO_1622473777517, WAIT=true, TAGS=tag1}, body=8], 消息内容 = TestMsg0
23:09:37.532 [http-nio-8080-exec-5] INFO c.k.t.r.MqController - [sendMsg,50] - mq producer 回调 time 20210531230937, result= SendResult [sendStatus=SEND_OK, msgId=C0A86D8000002A9F000000000000009A, messageQueue=MessageQueue [topic=TEST_TOPIC, brokerName=broker-a, queueId=1], queueOffset=0]
23:09:37.533 [ConsumeMessageThread_2] INFO c.k.t.r.PushConsumer - [consumeMessage,48] - mq Consumer1 time 20210531230937, 消息MessageExt [queueId=1, storeSize=154, queueOffset=0, sysFlag=0, bornTimestamp=1622473777518, bornHost=/192.168.109.1:49251, storeTimestamp=1622473776306, storeHost=/192.168.109.128:10911, msgId=C0A86D8000002A9F000000000000009A, commitLogOffset=154, bodyCRC=1602806610, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message [topic=TEST_TOPIC, flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=1, KEYS=HELLO_1622473777517, WAIT=true, TAGS=tag1}, body=8]], 消息内容 = TestMsg0
可以看到消息马上就被消费了,延迟很低。
在RocketMQ 控制台查看消息
PS: 安装 RocketMQ 的 NameServer,Broker,Console 使用docker安装 (推荐) 可参考 https://my.oschina.net/u/4213839/blog/5064591, 普通安装 https://my.oschina.net/u/4213839/blog/4965230