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,不然将会报错,这个错误虽然是可以解决的,但是会将出现一个别的错误,这个我将在下一个博客中说明.