首先要部署安装rocketmq服务, 安装教程请看上篇文章
切入正题,springboot 集成rocketmq 要pom引入rocketmq-client 注意一定和安装的rocketmq版本保持一致;
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.7.1</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-common</artifactId>
<version>4.7.1</version>
</dependency>
而后 编写Producer生产者初始化代码
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.common.protocol.heartbeat.MessageModel;
import org.springframework.stereotype.Component;
@Component
public class Producer {
private static String producerGroup = "test_producer_group";
private static DefaultMQProducer producer;
public static DefaultMQProducer getProducer() {
if (producer == null) {
/**
* 生产者group名
*/
producer = new DefaultMQProducer(producerGroup);
producer.setVipChannelEnabled(false);
/**
* Name Server 地址,因为是集群部署 所以有多个用 分号 隔开
*/
producer.setNamesrvAddr(RocketMqConfig.NAME_SERVER);
/**
* 主题名称 主题一般是服务器设置好 而不能在代码里去新建topic( 如果没有创建好,生产者往该主题发送消息 会报找不到topic错误)
*/
producer.setCreateTopicKey(RocketMqConfig.TOPIC);
try {
producer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
}
return producer;
}
/**
* 一般在应用上下文,使用上下文监听器,进行关闭
*/
public void shutdown(){
producer.shutdown();
}
consume 消费者代码
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
/**
* InitializingBean 项目启动时候加载
*/
@Component
public class Consumer implements InitializingBean {
/**
* 消费者实体对象
*/
private DefaultMQPushConsumer consumer;
/**
* 消费者组
*/
public static final String CONSUMER_GROUP = "test_consumer";
/**
*构造函数 实例化对象
*/
public DefaultMQPushConsumer getPushConsumer () {
if (null != consumer)
return consumer;
consumer = new DefaultMQPushConsumer(CONSUMER_GROUP);
consumer.setNamesrvAddr(RocketMqConfig.NAME_SERVER);
//消费模式:一个新的订阅组第一次启动从队列的最后位置开始消费
// 后续再启动接着上次消费的进度开始消费
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
/**
* 监听拉取消息
*/
consumer.registerMessageListener(new TestListenerConcurrently());
try {
consumer.subscribe(RocketMqConfig.TOPIC, "*");
consumer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
return consumer;
}
@Override
public void afterPropertiesSet() throws Exception {
DefaultMQPushConsumer consumer = getPushConsumer();
}
编写监听要实现
org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently接口 或者 org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly接口
他们之间主要区别是MessageListenerConcurrently 无序消费,MessageListenerOrderly 是顺序消费
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageExt;
import java.io.UnsupportedEncodingException;
import java.util.List;
/**
*
* 无序消费MessageListenerConcurrently
* 顺序消费MessageListenerOrderly
*
*/
public class TestListenerConcurrently implements MessageListenerConcurrently {
static final Log log = LogFactory.getLog(TestListenerConcurrently.class);
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
String body = null;
for (MessageExt messageExt : list) {
try {
body = new String(messageExt.getBody(), "utf-8");
// jsonMsg = JSON.parseObject(body);
log.info("consume收到消息:" + body);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
//消息消费失败 重新放入队列
reSendPushToMq(messageExt);
} catch (Exception e ) {
e.printStackTrace();
reSendPushToMq(messageExt);
}
}
//返回消费成功状态码 ,报错或者返回null broker 则会重新推消息,注意幂等性判断
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
/**
* 重新发 推送消息 发送到队列中
* @param message
*/
public void reSendPushToMq(Message message) {
try {
SendResult result = Producer.getProducer().send(message);
if (SendStatus.SEND_OK != result.getSendStatus()) {
log.error("reSendPushToMq > " + result.toString());
}
} catch (Exception e) {
log.error("reSendPushToMq Exception " + e.getMessage());
// reSendPushToMq(message);
}
}
}
测试类 这里方便测试就写了个定时任务 来定时生产消息
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Component
public class TaskController {
private static Logger logger = LoggerFactory.getLogger(TaskController.class);
@Scheduled(cron = "0/10 * * * * ?") // 每10s执行一次
public void task() throws Exception {
LocalDateTime localDateTime = LocalDateTime.now();
Thread.currentThread().setName(UUID.randomUUID().toString());
String msg=new StringBuffer().append(localDateTime + ":" + Thread.currentThread().getName()).toString();
org.apache.rocketmq.common.message.Message message=
new org.apache.rocketmq.common.message.Message(RocketMqConfig.TOPIC,msg.getBytes("utf-8"));
java.util.Random random= new java.util.Random(); // 定义随机类
int radnow=random.nextInt( 10 );
logger.info("radnow : " + radnow );
ExecutorService threadPool = ExecutorUtils.getTaskExecutor();
for (int i = 0; i <radnow; i++) {
SendResult result = Producer.getProducer().send(message);
//返回状态码 ok则发送成功
if(SendStatus.SEND_OK!=result.getSendStatus()){
logger.error(result.toString() );
} else {
logger.info(Thread.currentThread().getName() + " : 发送成功");
}
}
}
}
启动springboot 项目
同时,看 rocketmq-console 控制台消息
TIPS:遇到的问题
No route info of this topic TESTcotip
可能是pom引用 rocketmq-client版本不对