前言
在此只引入關鍵依賴,關於SpringBoot等其他基礎依賴請自行準備。
另外,本文中的實現方式爲點對點的方式。
開始
首先,在pom文件中引入依賴
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.2.0</version>
</dependency>
①一個Producer
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Slf4j
@Component
public class MessageProducer {
@Value(value = "${rocketMQ.address}")
private String address;
private DefaultMQProducer producer;
private static final Integer RETRY_TIMES = 5;
/**
* 消息生產者初始化
*/
@PostConstruct
private void init(){
try {
producer = new DefaultMQProducer("zxy");
producer.setNamesrvAddr(address);
producer.setInstanceName("MessageProducer");
producer.setRetryTimesWhenSendAsyncFailed(RETRY_TIMES);
producer.start();
} catch (Exception e){
log.error("消息生產者初始化失敗");
}
}
/**
* 消息生產者關閉
*/
@PreDestroy
public void destroy(){
try {
producer.shutdown();
} catch (Exception e){
log.error("消息生產者關閉失敗");
}
}
/**
* 異步發送mq
* @param topic
* @param tags
* @param body
*/
@Async
public void sendMessage(String topic, String tags, String body) {
try {
Message message = new Message(topic, tags, body.getBytes("UTF-8"));
producer.send(message, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
log.info("消息發送成功, sendResult:{}" , sendResult);
}
@Override
public void onException(Throwable throwable) {
Integer retryTimes = producer.getRetryTimesWhenSendAsyncFailed();
log.info("消息發送失敗, retryTimes:{}" , retryTimes);
}
});
} catch (Exception e) {
log.error("消息發送失敗,topic:{}, tags:{}, body:{}", topic, tags, body);
}
}
}
②一個Consumer
import com.zxy.devops.project.biz.enums.MessageTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Slf4j
@Component
public class DefaultConsumer {
@Value(value = "${rocketMQ.address}")
private String address;
@Autowired
private DefaultListener defaultListener;
@PostConstruct
public void messageSubscribe() throws Exception {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("DefaultConsumer");
consumer.setNamesrvAddr(address);
consumer.setInstanceName("DefaultConsumer");
consumer.subscribe("default-topic", "*");
consumer.registerMessageListener(defaultListener);
consumer.start();
log.info("Default consumer start.");
}
}
③一個Listener
import lombok.extern.slf4j.Slf4j;
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.common.message.Message;
import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.stereotype.Component;
import java.util.List;
@Slf4j
@Component
public class DefaultListener implements MessageListenerConcurrently {
private static final Integer RETRY_TIMES = 5;
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
log.info(Thread.currentThread().getName()
+" Receive New Messages: " + list.size());
Message message = list.get(0);
if (message == null) {
log.error("處理消息時, message 爲空");
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
log.info("處理消息 , topic={}, tags={}, keys={}, reConsumeTimes={}",
message.getTopic(),
message.getTags(),
message.getKeys(),
((MessageExt) message).getReconsumeTimes());
String defaultTag = "tag";
try {
//處理mq
if (defaultTag.equals(message.getTags())) {
//獲取消息body
String body = new String(message.getBody());
//TODO 執行業務邏輯
}
log.info("處理MQ消息消費 成功 , topic={}, tag={}, key={}, reConsumeTimes={}",
message.getTopic(),
message.getTags(),
message.getKeys(),
((MessageExt) message).getReconsumeTimes());
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
} catch (Exception e) {
log.error("處理MQ消息消費 保存記錄失敗,topic={}, tag={}, key={}, reConsumeTimes={}, body={},e={}",
message.getTopic(), message.getTags(), message.getKeys(), ((MessageExt) message).getReconsumeTimes(), new String(message.getBody()), e);
if (((MessageExt) message).getReconsumeTimes() < RETRY_TIMES) {
log.info("處理MQ,準備重新消費消息");
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
} else {
// 超過5次,就不重發了
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
}
}
}
總結
本文中實現了SpringBoot整合RocketMQ點對點的方式,其中Producer可通用向自定義topic生產消息,Consumer可自定義訂閱topic,如ConsumerA訂閱topic-A,ConsumerB訂閱topic-B。在本文中重試次數到達上限後,可另行添加補償機制,如生成日誌存入數據庫,後續批量處理。