一、配置文件
#該應用是否啓用生產者
rocketmq:
producer:
isOnOff: on
#發送同一類消息的設置爲同一個group,保證唯一,默認不需要設置,rocketmq會使用ip@pid(pid代表jvm名字)作爲唯一標示
groupName: ${spring.application.name}
#mq的nameserver地址
namesrvAddr: 127.0.0.1:9876
#消息最大長度 默認1024*4(4M)
maxMessageSize: 4096
#發送消息超時時間,默認3000
sendMsgTimeout: 3000
#發送消息失敗重試次數,默認2
retryTimesWhenSendFailed: 2
###consumer
##該應用是否啓用消費者
consumer:
isOnOff: on
groupName: ${spring.application.name}
#mq的nameserver地址
namesrvAddr: 127.0.0.1:9876
#該消費者訂閱的主題和tags("*"號表示訂閱該主題下所有的tags),格式:topic~tag1||tag2||tag3;topic2~*;
topics: futaotopic~*;
consumeThreadMin: 20
consumeThreadMax: 64
#設置一次消費消息的條數,默認爲1條
consumeMessageBatchMaxSize: 1
#失敗重試次數
reConsumerTimes: 3
二、生產者配置
/**
* @program: wx-job
* @description: RoceketMQ
* @author: pengyd
* @create: 2019-10-10 14:44
**/
@Configuration
@Slf4j
public class MQProducerConfig {
@Value("${rocketmq.producer.groupName}")
private String producerGroupName;
@Value("${rocketmq.producer.namesrvAddr}")
private String producerNameSrvAddr;
@Value("${rocketmq.producer.maxMessageSize}")
private int maxMessageSize;
@Value("${rocketmq.producer.sendMsgTimeout}")
private int sendMsgTimeout;
@Value("${rocketmq.producer.retryTimesWhenSendFailed}")
private int retryTimesWhenSendFailed;
@Bean
public DefaultMQProducer producer(){
if (this.producerGroupName.isEmpty()) {
throw new RuntimeException("producerGroupName isEmpty ");
}
if (this.producerNameSrvAddr.isEmpty()) {
throw new RuntimeException("producerNameSrvAddr isEmpty ");
}
DefaultMQProducer defaultMQProducer = new DefaultMQProducer(producerGroupName);
defaultMQProducer.setNamesrvAddr(producerNameSrvAddr);
defaultMQProducer.setMaxMessageSize(maxMessageSize);
defaultMQProducer.setSendMsgTimeout(sendMsgTimeout);
defaultMQProducer.setVipChannelEnabled(false);
//消息發送到mq服務器失敗重試次數
defaultMQProducer.setRetryTimesWhenSendFailed(retryTimesWhenSendFailed);
try {
defaultMQProducer.start();
log.info("rocketMq Producer start success; nameServer:{},producerGroupName:{}", producerNameSrvAddr, producerGroupName);
} catch (Exception e) {
log.error("rocketMq Producer start fail;{}", e.getMessage(), e);
}
return defaultMQProducer;
}
}
三、消費者配置
/**
* @program: wx-job
* @description: RoceketMQ
* @author: pengyd
* @create: 2019-10-10 14:44
**/
@Configuration
@Slf4j
public class MQConsumerConfig {
@Value("${rocketmq.consumer.namesrvAddr}")
private String consumerNamesrvAddr;
@Value("${rocketmq.consumer.groupName}")
private String consumerGroupName;
@Value("${rocketmq.consumer.consumeThreadMin}")
private int consumeThreadMin;
@Value("${rocketmq.consumer.consumeThreadMax}")
private int consumeThreadMax;
@Value("${rocketmq.consumer.topics}")
private String topics;
@Value("${rocketmq.consumer.consumeMessageBatchMaxSize}")
private int consumeMessageBatchMaxSize;
private static final String TOPIC = "test";
private static final String TAG = "test";
@Bean
public DefaultMQPushConsumer consumer() {
if (this.consumerGroupName.isEmpty()) {
throw new RuntimeException("consumerGroupName isEmpty ");
}
if (this.consumerNamesrvAddr.isEmpty()) {
throw new RuntimeException("consumerNamesrvAddr isEmpty ");
}
if (this.topics.isEmpty()) {
throw new RuntimeException("topics isEmpty ");
}
try {
//DefaultMQPushConsumer DefaultMQPullConsumer
DefaultMQPushConsumer defaultMQPushConsumer = new DefaultMQPushConsumer(consumerGroupName);
defaultMQPushConsumer.setNamesrvAddr(consumerNamesrvAddr);
defaultMQPushConsumer.setConsumeThreadMin(consumeThreadMin);
defaultMQPushConsumer.setVipChannelEnabled(false);
// defaultMQPushConsumer.createTopic();
defaultMQPushConsumer.setConsumeThreadMax(consumeThreadMax);
//消費模式 集羣還是廣播,默認爲集羣(自動負載均衡)
//廣播消費: 消息會發給Consume Group中的每一個消費者進行消費,如果設置爲廣播消息會導致NOT_ONLINE異常,https://github.com/apache/rocketmq/issues/296
defaultMQPushConsumer.setMessageModel(MessageModel.CLUSTERING);
//設置Consumer第一次啓動是從隊列頭部開始消費還是隊列尾部開始消費
//如果非第一次啓動,那麼按照上次消費的位置繼續消費
defaultMQPushConsumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
//設置一次消費消息的條數,默認爲1條
defaultMQPushConsumer.setConsumeMessageBatchMaxSize(consumeMessageBatchMaxSize);
//訂閱topic
defaultMQPushConsumer.subscribe(TOPIC, TAG);
//defaultMQPushConsumer.registerMessageListener(mqMessageListenerProcessor)
defaultMQPushConsumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
MessageExt msg = list.get(0);
System.out.println("接收到的消息爲:" + new String(msg.getBody(), StandardCharsets.UTF_8));
if (msg.getTopic().equals(TOPIC) && msg.getTags().equals(TAG)) {
//判斷該消息是否重複消費(RocketMQ不保證消息不重複,如果你的業務需要保證嚴格的不重複消息,需要你自己在業務端去重)
//獲取該消息重試次數
if (msg.getReconsumeTimes() >= 3) {
//消息已經重試了3次,如果不需要再次消費,則返回成功
//TODO("如果重試了三次還是失敗則執行對於失敗的業務邏輯")
log.error("消息重試消費失敗:{}", msg);
System.out.println(ConsumeConcurrentlyStatus.CONSUME_SUCCESS);
} else {
//如果失敗重試次數還沒到三次則繼續重試
System.out.println(ConsumeConcurrentlyStatus.RECONSUME_LATER);
}
//TODO("開始正常的業務邏輯")
System.out.println("開始正常的業務邏輯:" + new String(msg.getBody(), StandardCharsets.UTF_8));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
defaultMQPushConsumer.start();
log.info("rocketMq Consumer start success; namesrvAddr:{},groupName:{},topics:{}", consumerNamesrvAddr, consumerGroupName, topics);
return defaultMQPushConsumer;
} catch (Exception e) {
log.error("rocketMq Consumer start fail;{}", e.getMessage(), e);
return new DefaultMQPushConsumer();
}
}
四、簡單使用
/**
* FileName: MQController
* Author: pengyd
* Date: 2019/12/26
* function:
*/
@RequestMapping("/mq")
@Controller
public class MQController {
private static Logger logger = LoggerFactory.getLogger(MQController.class);
@Resource
private DefaultMQProducer producer;
@RequestMapping("/mqSend")
@ResponseBody
public String mqSend() {
logger.info("開始發送rocketmq");
//組裝消息內容
Message message = new Message("test",
"test",
(new Date().toString() + "這是測試mq").getBytes());
try {
producer.send(message);
} catch (Exception e) {
e.printStackTrace();
}
return "success";
}
}
五、over