RocketMQ很好使,如果用同一個消費組來消費多個topic時,我們需要先將所要監聽的topic綁定到消費組上,然後就可以監聽了,但是這種寫法適合於用一個消費組,後期每添加一個topic就會多一個if-else來判斷,所以有了下面這種方法.
第一步:首先我們定義一個BaseConsumer
public abstract class BaseConsumer {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
private DefaultMQPushConsumer consumer;
protected String namesrvAddr;
protected String consumerGroup;
protected String topic;
protected String subExpression;
//最小線程
protected int consumeThreadMin;
//最大線程
protected int consumeThreadMax;
protected BaseConsumer(String namesrvAddr, String topic, String consumerGroup, String subExpression,int consumeThreadMin,int consumeThreadMax){
this.namesrvAddr = namesrvAddr;
this.consumerGroup = consumerGroup;
this.topic = topic;
this.subExpression = subExpression;
this.consumeThreadMin = consumeThreadMin;
this.consumeThreadMax = consumeThreadMax;
}
protected abstract boolean consumeMsg(List<MessageExt> msgs,ConsumeConcurrentlyContext context);
@PostConstruct
public final void start() throws MQClientException{
consumer = new DefaultMQPushConsumer();
consumer.setConsumerGroup(this.consumerGroup);
consumer.setNamesrvAddr(this.namesrvAddr);
consumer.subscribe(topic, subExpression);
consumer.setConsumeThreadMin(this.consumeThreadMin);
consumer.setConsumeThreadMax(this.consumeThreadMax);
consumer.setInstanceName(RuntimeUtil.getRocketMqUniqeInstanceName());
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
//設置大於4次後就不消費了
if (msgs.get(0).getReconsumeTimes() > 4) {
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
return consumeMsg(msgs,context)?ConsumeConcurrentlyStatus.CONSUME_SUCCESS:ConsumeConcurrentlyStatus.RECONSUME_LATER;
});
consumer.start();
}
@PreDestroy
public final void destroy(){
consumer.shutdown();
}
}
第二步:再寫個需要使用的消費者,繼承它.
public class TestConsumer extends BaseConsumer {
public TestConsumer(String namesrvAddr, String topic, String consumerGroup, String subExpression, int consumeThreadMin, int consumeThreadMax) {
super(namesrvAddr, topic, consumerGroup, subExpression, consumeThreadMin, consumeThreadMax);
}
@Override
protected boolean consumeMsg(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
MessageExt msg = msgs.get(0);
// 當前的偏移量
// long offset = msg.getQueueOffset();
// String maxOffset = msg.getProperty(MessageConst.PROPERTY_MAX_OFFSET);
// 當前的未消費量
// long diff = Long.parseLong(maxOffset) - offset;
String message = new String(msg.getBody(), StandardCharsets.UTF_8);
logger.info("test:{}", message);
return true;
}
}
第三步:然後聲明個Bean,把自己的mq地址,topic,consumerGroup,tag,線程數,填入裏面,即可食用.
@Configuration
public class BeanConfig {
@Bean
public TestConsumer testConsumer() {
return new TestConsumer(namesrvAddr,
"TopicTest",
"TestCG",
"*",
5,
10);
}
}
這種方法好處在於,再加入新的topic時,可以直接繼承BaseConsumer即可,比較方便管理,不再監聽某一Topic時,可以直接將@Bean
註釋掉就可以了.
但是有一點需要注意,每增加一個新的Topic,你需要用一個新的ConsumerGroup,不然將會報錯,這個錯誤雖然是可以解決的,但是會將出現一個別的錯誤,這個我將在下一個博客中說明.