SpringBoot集成RocketMQ之模版方法模式

前言

我们经常使用RocketMQ来进行业务逻辑的解藕,或者在分布式环境下,用来进行系统之间的通信。相比于Kafka、Rabbitmq等其他消息中间件,RocketMQ有很多优势特性,这里就不一一介绍了,可以去官网上查看各种mq的优劣对比。

使用与封装

RocketMQ使用起来十分简单与便捷,官网上也有很多示例,但是我们系统中往往不止一个生产者/消费者实例。这时候,就需要封装一下,一来可以统一逻辑、二来减少重复的代码,没必要去单独的配置每个生产者/消费者。

基于模版方法的封装

我们首先来看看,一个简单的消费者实例(生产者其实不需要特别的封装,不同的生产者区别在于topic以及发送的消息体,而这两个,是作为发送消息的方法签名的参数,因此整个项目可以使用同一个生产者,这里就不细述了)。

		// 实例化消费者
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");

    	// 设置NameServer的地址
        consumer.setNamesrvAddr("localhost:9876");

    	// 订阅一个或者多个Topic,以及Tag来过滤需要消费的消息
        consumer.subscribe("TopicTest", "*");
    	// 注册回调实现类来处理从broker拉取回来的消息
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
                System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
                // 标记该消息已经被成功消费
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        // 启动消费者实例
        consumer.start();

可以看到,启动一个消费者大概需要5步:
1、实例化一个消费者,同时指定消费者组
2、设置NameServer地址
3、订阅topic
4、注册消息的处理实现类
5、启动消费者
上述5步,除了1、3、4步有一些区别,其余的逻辑是一样的。那么我们可以使用模版方法的模式来封装消费者。模版方法的优点在于,将实现延迟到子类,由子类提供某些方法的具体实现。这样就可以实现差异化。
首先设计一个模版基类:

/**
 * @author zhaosheng
 * @version v1.0
 * @description: 消费者实例基类,具体实例不继承此类,而是继承${@link BaseConcurrentlyConsumer},这里将类的访问权限设置为包权限,就是为了防止直接继承此类
 * @date 2020/9/2 9:45 下午
 */
abstract class BaseRocketMQConsumer {

    @Value("${rocketMq.namesrvAddr}")
    private String namesrvAddr;

    protected final DefaultMQPushConsumer consumer;

    public BaseRocketMQConsumer() {
        this.consumer = new DefaultMQPushConsumer();
    }

    /**消费者组*/
    protected abstract String getConsumerGroup();
    /**topic*/
    protected abstract String getTopic();
    /**tags*/
    protected abstract String getTags();
    /**处理从broker拉取的消息*/
    protected abstract boolean handleMsg(String msg);

    /**这个方法会在子类的构造方法*/
    protected void start() throws MQClientException {
        this.consumer.setConsumerGroup(getConsumerGroup());
        this.consumer.setNamesrvAddr(namesrvAddr);
        this.consumer.subscribe(getTopic(), getTags());
        this.consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
        this.consumer.start();
    }
}

由于消费者消费消息的方式可以分为并发消费顺序消费,因此上面的基类中并没有注册消息的回调实现类,而是会再设计一个并发者基类,如下所示:

@Slf4j
public abstract class BaseConcurrentlyConsumer extends BaseRocketMQConsumer {

    /**并发消费方式的回调实现类*/
    private final MessageListenerConcurrently messageListenerConcurrently = (msgList, consumeConcurrentlyContext) -> {
        MessageExt messageExt = msgList.get(0);
        String msg = new String(messageExt.getBody());
        log.info("{} receive msg: topic={}, tag={}, msgId={}, body={}",
                Thread.currentThread().getName(), messageExt.getTopic(), messageExt.getTags(),
                messageExt.getMsgId(), msg);
        //handelMsg()为实际业务处理的类,onMsg()为实际处理消息的方法
        boolean result = handleMsg(msg);
        return result ? ConsumeConcurrentlyStatus.CONSUME_SUCCESS : ConsumeConcurrentlyStatus.RECONSUME_LATER;
    };

    public BaseConcurrentlyConsumer() throws MQClientException {
        //注册回调实现类
        super.consumer.registerMessageListener(messageListenerConcurrently);
        super.start();
    }
}

下面我们来实现一个具体的消费者实例:

@Component
public class ExampleConsumer extends BaseConcurrentlyConsumer {

    public ExampleConsumer() throws MQClientException {
    }

    @Override
    protected String getConsumerGroup() {
        return "templateConsumerGroup";
    }

    @Override
    protected String getTopic() {
        return "templateTopic";
    }

    @Override
    protected String getTags() {
        return "*";
    }

	@override
    protected boolean handleMsg(String msg) {
        System.out.println("收到消息:" + msg);
        return true;
    }

}

以上就是使用模版方法来实现的RocketMQ消费者的封装,对于每个消费者,将其相同的步骤放到父类去实现,子类只需要关注具体的消息消费逻辑以及消费者组、消费的topic和过滤的tags即可。

你可能感兴趣的:(RocketMQ,spring,boot,spring,boot,rocketmq)