springboot整合rocketMQ项目实战

1.首先引入pom.xml依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--简化POJO的对象中冗余代码-->
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<optional>true</optional>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
</dependency>
<!--引入rocketmq依赖-->
<dependency>
	<groupId>org.apache.rocketmq</groupId>
	<artifactId>rocketmq-spring-boot-starter</artifactId>
	<version>2.0.3</version>
</dependency>

2.配置springboot中的application.yml文件:

spring:
  application:
    name: boot-rocketmq-demo

rocketmq:
  name-server: 121.36.197.6:9876;116.85.44.178:9876;121.36.166.118:9876;121.36.144.49:9876
  producer:
    #生产者组名,规定在一个应用里面必须时唯一的(这里直接引用项目名称,或者自定义唯一组名)。
    group: ${spring.application.name}
    #消息发送的超时时间,毫米级别,默认为3S
    send-message-timeout: 3000
    #消息达到4096字节的时候,消息就会被压缩。默认就是4096,有利于网络传输,提升性能。
    compress-message-body-threshold: 4096
    #最大的消息限制 默认为128K
    max-message-size: 4194304
    #同步消息发送失败重试次数
    retry-times-when-send-failed: 3
    #在内部发送失败时是否重试其他代理。 源码:setRetryAnotherBrokerWhenNotStoreOK,就是指:发送到broker-a失败是否发送到broker-b。这个参数在有多个broker才生效。
    retry-next-server: true
    #异步消息发送失败重试的次数
    retry-times-when-send-async-failed: 3

3.如果存在分布式事务消息发送可以配置一个Listener(项目不存在分布式事务管理可不配置):

package com.zl.integraterocketmq.listener;

import com.zl.integraterocketmq.entity.OrderPaidEventTx;
import com.zl.integraterocketmq.util.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
import org.springframework.messaging.Message;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * 存在分布式事务消息发送配置事务监听
 * @Author: Tom
 * @Date: 2019/7/11 20:13
 */
@Slf4j
@RocketMQTransactionListener(txProducerGroup = "test-txProducerGroup-name")
public class TransactionListenerImpl implements RocketMQLocalTransactionListener {

    /**
     * RocketMQLocalTransactionState说明:
     *
     * COMMIT:
     *         表示事务消息被提交,会被正确分发给消费者。(事务消息先会发送到broker,对消费端不可见,为UNKNOWN状态,在这里回调的时候如果返回COMMIT
     *         那么。消费端马上就会接收到消息。)
     *
     * ROLLBACK:
     *          该状态表示该事务消息被回滚,因为本地事务逻辑执行失败导致(如数据库异常,或SQL异常,或其他未知异常,这时候消息在broker会被删除掉,
     *          不会发送到consumer)
     * UNKNOWN:
     *        表示事务消息未确定,可能是业务方执行本地事务逻辑时间耗时过长或者网络原因等引起的,该状态会导致broker对事务消息进行回查,默认回查
     *        总次数是15次,第一次回查间隔时间是6s,后续每次间隔60s,(消息一旦发送状态就为中间状态:UNKNOWN)
     */


    /**
     * 执行本地的事务逻辑
     *
     * @param msg
     * @param arg
     * @return
     */
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        log.info("执行本地事务逻辑:{}", msg);
        CountDownLatch latch = null;
        try {
            latch = (CountDownLatch) arg;
            byte[] body = (byte[]) msg.getPayload();
            String json = new String(body, RemotingHelper.DEFAULT_CHARSET);
            OrderPaidEventTx orderPaidEventTx = JsonUtil.jsonToObject(json, OrderPaidEventTx.class);

            //执行本地事务,比如下单成功,存储订单信息。
            assert orderPaidEventTx != null;
            log.info("执行本地事务接收到到的消息内容为:{}", orderPaidEventTx.toString());

            //模拟现实中的业务逻辑
            TimeUnit.SECONDS.sleep(2);

            //本地事务执行成功。
            return RocketMQLocalTransactionState.COMMIT;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("本地事务执行失败:如数据库异常,或SQL异常,或其他未知异常,异常原因:{}", e.getMessage());
            return RocketMQLocalTransactionState.ROLLBACK;
        } finally {
            if (null != latch) {
                //事务提交完成,或代码执行完成一定要把CountDownLatch 归0,不然会造成主线程阻塞。
                latch.countDown();
            }
        }
    }

    /**
     * 执行事务回查逻辑
     *
     * @param msg
     * @return
     */
    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        //6s 本地事务还没执行完成,就会触发回调检查的方法。

        //这时候就要做自己对这个订单的异常处理,最后根据处理的情况来决定,
        // 重新发送这个订单到消费者 还是删除还是继续回查。

//     如:   return RocketMQLocalTransactionState.COMMIT; 重新发送到消费端
//        return RocketMQLocalTransactionState.ROLLBACK;  消费在broker删除,不会发送到消费端
        return null;
    }
}

4.配置完成进行实操(controller层):

package com.zl.integraterocketmq.controller;

import com.zl.integraterocketmq.service.GeneralMQMessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author: Tom
 * @Date: 2019/7/11 14:12
 * @Desc: 对 RocketMQTemplate 封装原始rocketMq 一些常用方法的示例和测试。
 * 结合官方源码和README_zh_CN.md 看。
 * rocketmq-spring-boot-starter 源码地址:https://github.com/apache/rocketmq-spring
 */
@RestController
@RequestMapping("/rocketMq")
public class MQMessageController {

	/**service接口引入,具体消息发送在接口实现类中进行**/
    @Autowired
    private GeneralMQMessageService generalMQMessageService;

    /**
     * rocketMq同步消息发送测试
     */
    @RequestMapping("/syncGeneralMQMessageSend")
    public void syncGeneralMQMessageSend() {
        generalMQMessageService.syncGeneralMQMessageSend();
    }

    /**
     * rocketMq异步消息发送测试
     */
    @RequestMapping("/asyncSendMQMessageSend")
    public void asyncSendMQMessageSend() {
        generalMQMessageService.asyncSendMQMessageSend();
    }

    /**
     * rocketMq单向发送不关心结果的发送测试【日志收集】
     */
    @RequestMapping("/oneWaySendMQMessageSend")
    public void oneWaySendMQMessageSend() {
        generalMQMessageService.oneWaySendMQMessageSend();
    }

    /**
     * 延迟消息发送测试
     */
    @RequestMapping("/delayedSendMQMessageSend")
    public void delayedSendMQMessageSend() {
        generalMQMessageService.delayedSendMQMessageSend();
    }

    /**
     * 顺序消息发送
     */
    @RequestMapping("/orderlyMQMessageSend")
    public void orderlyMQMessageSend() {
        generalMQMessageService.orderlyMQMessageSend();
    }

    /**
     * 分布式事务消息发送
     */
    @RequestMapping("/transactionMQSend")
    public void transactionMQSend() {
        generalMQMessageService.transactionMQSend();
    }

    /**
     * 消息过滤消息发送
     */
    @RequestMapping("/selectorMQSend")
    public void selectorMQSend() {
        generalMQMessageService.selectorMQSend();
    }
}

5.service层接口:

package com.zl.integraterocketmq.service;

/**
 * @Author: Tom
 * @Date: 2019/7/11 13:37
 * @Desc rocketMQ 普通消息发送示例
 */
public interface GeneralMQMessageService {
    /**
     * rocketMQ发送同步消息测试
     */
    void syncGeneralMQMessageSend();

    /**
     * rocketMQ异步消息发送测试
     */
    void asyncSendMQMessageSend();

    /**
     * rocketMq单向发送测试
     */
    void oneWaySendMQMessageSend();

    /**
     * 延迟消息测试
     */
    void delayedSendMQMessageSend();

    /**
     * 顺序消息发送
     */
    void orderlyMQMessageSend();

    /**
     * 分布式事务消息发送测试
     */
    void transactionMQSend();

    /**
     * 消息过滤发送
     */
    void selectorMQSend();
}

6.service层接口实现类(生产者生产并发送消息):

package com.zl.integraterocketmq.service.impl;

import com.zl.integraterocketmq.constant.MessageDelayLevel;
import com.zl.integraterocketmq.entity.OrderPaidEvent;
import com.zl.integraterocketmq.entity.OrderPaidEventTx;
import com.zl.integraterocketmq.service.GeneralMQMessageService;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.*;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;

/**
 * 同步及异步在项目中使用较多,其他根据需求使用
 * @Author: Tom
 * @Date: 2019/7/11 13:37
 */
@Slf4j
@Service
public class GeneralMQMessageServiceImpl implements GeneralMQMessageService {

	/**引入RocketMQ接口**/
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 同步发送的方式:
     * <p>
     * 指消息发送方发出数据后,会在收到接收方发回响应之后才发下一个数据包的通讯方式。
     */
    @Override
    public void syncGeneralMQMessageSend() {

        //发送string类型的消息 : SendResult syncSend(String destination, Object payload);
        //对应消费者:SyncGeneralMQConsumer1
        String stringTopic = "string-topic";
        String payloadStr = "Hello world!";
        SendResult sendResultStr = rocketMQTemplate.syncSend(stringTopic, payloadStr);
        log.info("MQ同步发送String类型的消息topic为:{},返回结果:{}", stringTopic, sendResultStr);

        //发送对象类型的消息 :  SendResult syncSend(String destination, Message<?> message);
        //对应消费者:SyncGeneralMQConsumer2
        String objectTopic = "object-topic";
        OrderPaidEvent orderPaidEvent = new OrderPaidEvent();
        orderPaidEvent.setOrderId("123456789");
        orderPaidEvent.setPaidMoney(new BigDecimal(20));
        Message<OrderPaidEvent> message = MessageBuilder.withPayload(orderPaidEvent).build();
        Message<OrderPaidEvent> build = MessageBuilder.withPayload(orderPaidEvent).setHeader("", "").build();
        SendResult sendResultObj = rocketMQTemplate.syncSend(objectTopic, message);
        log.info("MQ同步发送对象类型(对象放到MessageBuilder构建)的消息topic为:{},返回结果:{}", stringTopic, sendResultObj);

        //发送对象类型的消息: SendResult syncSend(String destination, Object payload); convertAndSend 也可以发送消息,但是返回值为void
        //对应消费者:SyncGeneralMQConsumer2
        OrderPaidEvent orderPaidEvent1 = new OrderPaidEvent();
        orderPaidEvent1.setOrderId("987654321");
        orderPaidEvent1.setPaidMoney(new BigDecimal(50));
        SendResult sendResultObj1 = rocketMQTemplate.syncSend(objectTopic, orderPaidEvent1);
        log.info("MQ同步发送对象类型(直接传入对象)消息topic:{},返回结果:{}", stringTopic, sendResultObj1);

    }

    /**
     * 异步发送:
     * 指发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。
     * MQ 的异步发送,需要用户实现异步发送回调接口(SendCallback),在执行消息的异步发送时,
     * 应用不需要等待服务器响应即可直接返回,通过回调接口接收务器响应,并对服务器的响应结果进行处理。
     */
    @Override
    public void asyncSendMQMessageSend() {

        String objectTopic = "object-topic";
        OrderPaidEvent orderPaidEvent = new OrderPaidEvent();
        orderPaidEvent.setOrderId("123456789");
        orderPaidEvent.setPaidMoney(new BigDecimal(20));
        rocketMQTemplate.asyncSend(objectTopic, orderPaidEvent, new SendCallback() {
            @Override
            public void onSuccess(SendResult sendResult) {
                log.info("异步消息发送成功:{}", sendResult);
            }

            @Override
            public void onException(Throwable throwable) {
                log.error("异步消息发送失败:{}", throwable.getCause());
            }
        });
    }

    /**
     * 特点为只负责发送消息,不等待服务器回应且没有回调函数触发,即只发送请求不等待应答。
     * <p>
     * 此方式发送消息的过程耗时非常短,一般在微秒级别。
     * <p>
     * 应用场景:适用于某些耗时非常短,但对可靠性要求并不高的场景,例如日志收集。
     * <p>
     * 与异步发送的区别在于:异步其实还是要发送结果,不过是回调回来,不阻塞当前线程等待结果。
     */
    @Override
    public void oneWaySendMQMessageSend() {

        String objectTopic = "object-topic";
        OrderPaidEvent orderPaidEvent = new OrderPaidEvent();
        orderPaidEvent.setOrderId("123456789");
        orderPaidEvent.setPaidMoney(new BigDecimal(20));
        rocketMQTemplate.sendOneWay(objectTopic, orderPaidEvent);

    }

    /**
     * 延迟消息:
     * rocketMQ的延迟消息发送其实是已发送就已经到broker端了,然后消费端会延迟收到消息。
     * <p>
     * RocketMQ 目前只支持固定精度的定时消息。
     * 延迟级别(18个等级)
     * 1到18分别对应1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
     * <p>
     * 为什么不支持固定精度的定时消息?
     * 因为rocketMQ之所以性能好的原因是broker端做的事情很少,基本都交给业务端做,就是消费端。如果支持
     * 我们自定义的延迟时候,会很大程度消耗broker的性能。
     * <p>
     * 延迟的底层方法是用定时任务实现的。
     */
    @Override
    public void delayedSendMQMessageSend() {
        //SendResult syncSend(String destination, Message<?> message, long timeout, int delayLevel);
        String objectTopic = "object-topic";
        OrderPaidEvent orderPaidEvent = new OrderPaidEvent();
        orderPaidEvent.setOrderId("123456789");
        orderPaidEvent.setPaidMoney(new BigDecimal(20));
        Message<OrderPaidEvent> message = MessageBuilder.withPayload(orderPaidEvent).build();
        //这里的2就是对应上面延迟5s的。就是延迟5s发送消息。
        SendResult sendResult = rocketMQTemplate.syncSend(objectTopic, message, 1000, MessageDelayLevel.TIME_5S);
        log.info("发送延迟消息返回结果:{}", sendResult);
    }

    @Override
    public void orderlyMQMessageSend() {

        //public SendResult syncSendOrderly(String destination, Object payload, String hashKey);
        String orderlyTopic = "orderly-topic";

        //同步顺序发送 - 对应顺序消费:
        for (int i = 0; i < 5; i++) {

            OrderPaidEvent orderPaidEvent = new OrderPaidEvent();
            String orderId = "123456";
            orderPaidEvent.setOrderId(orderId);
            orderPaidEvent.setPaidMoney(new BigDecimal(20));
            orderPaidEvent.setOrderly(i);

            // 源码导读:
            // * @param hashKey    use this key to select queue. for example: orderId, productId ...
            // 翻译过来为: 使用这个hashKey去选择投递到哪个队列,比如可以设置为:orderId 或则 productId
            // FAQ:rocketMQ创建topic的时候默认的队列长度为16个,那么这个hashKey,怎么通过自己设置的orderId或则producId变成队列标示的比如如果16和队列这个值应该在1-16之间?
            // 继续看源码:
            // List<MessageQueue> messageQueueList = mQClientFactory.getMQAdminImpl().parsePublishMessageQueues(topicPublishInfo.getMessageQueueList());
            // 上面这个方法就能获取这个topic创建的时候的队列长度。然后根据它底层有个取模的方法 取到其中一个队列
            // 取模的算法很简单 :org.apache.rocketmq.client.producer.selector.SelectMessageQueueByHash.select
            // 所以为什么这个方法的源码说我们的hashkey可以设置为:orderId和productId,这样同样的orderId就可以进入同一个队列 按照顺序消费
            //EX:顺序消费的底层源码实现就是必须选择一个队列,然后在这个对面里面的消息和生产顺序保持一致。

            SendResult sendResult = rocketMQTemplate.syncSendOrderly(orderlyTopic, orderPaidEvent, orderId);
            log.info("同步发送顺序消息返回结果:{}", sendResult);
        }

        //异步顺序发送 - 对应顺序消费:
        for (int i = 0; i < 5; i++) {

            OrderPaidEvent orderPaidEvent = new OrderPaidEvent();
            String orderId = "654321";
            orderPaidEvent.setOrderId(orderId);
            orderPaidEvent.setPaidMoney(new BigDecimal(20));
            orderPaidEvent.setOrderly(i);

            rocketMQTemplate.asyncSendOrderly(orderlyTopic, orderPaidEvent, orderId, new SendCallback() {
                @Override
                public void onSuccess(SendResult sendResult) {
                    log.info("异步发送顺序返回结果为:{}", sendResult);
                }

                @Override
                public void onException(Throwable e) {
                    log.error("异步发送顺序消息失败,原因为:{}", e.getCause());
                }
            });

        }
    }

    /**
     * 分布式事务消息发送
     */
    @Override
    public void transactionMQSend() {

        //消息发送回调:com.zl.integraterocketmq.listener.TransactionListenerImpl
        String txProducerGroup = "test-txProducerGroup-name";
        //topic:tag
        String destination = "tx-text-topic";

        //同步阻塞
        CountDownLatch latch = new CountDownLatch(1);
        OrderPaidEventTx orderPaidEventTx = new OrderPaidEventTx();
        orderPaidEventTx.setOrderId("123456");
        orderPaidEventTx.setPaidMoney(new BigDecimal(20));

        String transactionId = UUID.randomUUID().toString();
        Message<OrderPaidEventTx> message = MessageBuilder
                .withPayload(orderPaidEventTx)
                .setHeader(RocketMQHeaders.TRANSACTION_ID, transactionId)
                .setHeader(RocketMQHeaders.KEYS, orderPaidEventTx.getOrderId())
                .build();
//      sendMessageInTransaction(final String txProducerGroup, final String destination, final Message<?> message, final Object arg)
        TransactionSendResult sendResult = rocketMQTemplate.sendMessageInTransaction(txProducerGroup, destination, message, latch);

        if (sendResult.getSendStatus().equals(SendStatus.SEND_OK)
                && sendResult.getLocalTransactionState().equals(LocalTransactionState.COMMIT_MESSAGE)) {
            //下单成功,并且消息对消费端可见。

            //在这里可以异步通知上游服务,也可以继续走自己的逻辑,比如有些逻辑必须保证下单和库存成功之后才能走的。

            log.info("消息发送成功,并且本地事务执行成功");
        }
        try {
            latch.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void selectorMQSend() {
        for (int i = 0; i < 5; i++) {
            Random random = new Random();
            int k = random.nextInt(3) % 2;
            OrderPaidEvent orderPaidEvent = new OrderPaidEvent();

            orderPaidEvent.setOrderId("123456");

            String selectorTopic = "selector_topic";
            String tag = k == 0 ? ":tag1" : ":tag2";
            SendResult sendResult = rocketMQTemplate.syncSend(selectorTopic + tag, orderPaidEvent);
            log.info("消息过滤发送成功返回结果为:{},当前k的参数值为:{}", sendResult, k);
        }
    }
}

6.实体类

package com.zl.integraterocketmq.entity;

import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
/**
 * @Author: Tom
 * @Date: 2019/7/11 14:41
 */
@Data
public class OrderPaidEvent implements Serializable {

    private static final long serialVersionUID = -8983677932582480532L;

    private String orderId;

    private BigDecimal paidMoney;

    private Integer orderly;
}

package com.zl.integraterocketmq.entity;

import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;

/**
 * @Author: Tom
 * @Date: 2019/7/11 20:10
 */
@Data
public class OrderPaidEventTx implements Serializable {

    private static final long serialVersionUID = 6785405514983538778L;

    private String orderId;

    private BigDecimal paidMoney;
}

7.消费者消费接口:

package com.zl.integraterocketmq.consumer;

import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
 * @Author: Tom
 * @Date: 2019/7/11 14:52
 * @Desc: RocketMQ在设计时就不希望一个消费者同时处理多个类型的消息,
 * 因此同一个consumerGroup下的consumer职责应该是一样的,
 * 不要干不同的事情(即消费多个topic)。建议consumerGroup与topic一一对应。
 *
 * https://github.com/apache/rocketmq-spring/blob/master/README_zh_CN.md FAQ:3
 */
@Slf4j
@Service
/**注意topic = "string-topic"中字符串要与消息发送字符串一致
	RocketMQListener<String>中String与消息发送类型一致,可以为字符串,对象等
**/
@RocketMQMessageListener(topic = "string-topic", consumerGroup = "my-consumer_string-topic")
public class SyncGeneralMQConsumer1 implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        log.info("SyncGeneralMQConsumer1端接收到消息:{}", message);
    }
}

package com.zl.integraterocketmq.consumer;

import com.zl.integraterocketmq.entity.OrderPaidEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
 * @Author: Tom
 * @Date: 2019/7/11 14:57
 * @Desc: RocketMQ在设计时就不希望一个消费者同时处理多个类型的消息,
 * 因此同一个consumerGroup下的consumer职责应该是一样的,
 * 不要干不同的事情(即消费多个topic)。建议consumerGroup与topic一一对应。
 * https://github.com/apache/rocketmq-spring/blob/master/README_zh_CN.md FAQ:3
 */
@Slf4j
@Service
@RocketMQMessageListener(topic = "object-topic", consumerGroup = "my-consumer_object-topic")
public class SyncGeneralMQConsumer2 implements RocketMQListener<OrderPaidEvent> {

    @Override
    public void onMessage(OrderPaidEvent message) {
        log.info("SyncGeneralMQConsumer2 消费端接收到消息:{}", message.toString());
    }
}

package com.zl.integraterocketmq.consumer;

/**
 * @Author: zhouliang
 * @Date: 2019/7/11 18:42
 */

import com.zl.integraterocketmq.entity.OrderPaidEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
 * @Author: Tom
 * @Date: 2019/7/11 14:52
 * @Desc: RocketMQ在设计时就不希望一个消费者同时处理多个类型的消息,
 * 因此同一个consumerGroup下的consumer职责应该是一样的,
 * 不要干不同的事情(即消费多个topic)。建议consumerGroup与topic一一对应。
 * <p>
 * 顺序消费消费者需要设置为:consumeMode : ConsumeMode.ORDERLY
 * <p>
 * 注意:消费者默认实现的接口为MessageListenerConcurrently, 对应为ConsumeMode.CONCURRENTLY
 * 消费者实现MessageListenerOrderly的时候,就是为顺序消费。
 */
@Slf4j
@Service
@RocketMQMessageListener(consumeMode = ConsumeMode.ORDERLY, topic = "orderly-topic", consumerGroup = "my-consumer_orderly-topic")
public class OrderlyMQConsumer implements RocketMQListener<OrderPaidEvent> {

    @Override
    public void onMessage(OrderPaidEvent message) {
        log.info("MQ顺序测试消费端接收到消息:{}", message.toString());
    }
}

package com.zl.integraterocketmq.consumer;

import com.zl.integraterocketmq.entity.OrderPaidEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.annotation.SelectorType;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
 * @Author: Tom
 * @Date: 2019/7/12 11:06
 */
@Slf4j
@Service
@RocketMQMessageListener(consumeMode = ConsumeMode.CONCURRENTLY, selectorType = SelectorType.TAG, topic = "selector_topic",
        consumerGroup = "my-consumer_selector_topic", selectorExpression = "tag1")
public class SelectorMQConsumer implements RocketMQListener<OrderPaidEvent> {

    @Override
    public void onMessage(OrderPaidEvent message) {
        log.info("tag1======>>消息过滤消费端接收到消息:{}", message);
    }
}

package com.zl.integraterocketmq.consumer;

import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
 * @Author: Tom
 * @Date: 2019/7/11 14:52
 */
@Slf4j
@Service
@RocketMQMessageListener(consumeMode = ConsumeMode.ORDERLY, topic = "gantry_data_sync_topic", consumerGroup = "my_test_group1")
public class CanalMQConsumer implements RocketMQListener<MessageExt> {

    @Override
    public void onMessage(MessageExt message) {
        try {
            String msg = new String(message.getBody(), RemotingHelper.DEFAULT_CHARSET);
            log.info("canal gantry ===>>>> {}", msg);
        } catch (Exception e) {
            log.error("", e);
        }
    }
}

package com.zl.integraterocketmq.consumer;

import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
 * @Author: Tom
 * @Date: 2019/7/11 14:52
 */
@Slf4j
@Service
@RocketMQMessageListener(consumeMode = ConsumeMode.ORDERLY, topic = "united_order_data_sync_topic", consumerGroup = "my_test_group2")
public class CanalMQConsumer2 implements RocketMQListener<MessageExt> {

    @Override
    public void onMessage(MessageExt message) {
        try {
            String msg = new String(message.getBody(), RemotingHelper.DEFAULT_CHARSET);
            log.info("canal united ===>>>> {}", msg);
        } catch (Exception e) {
            log.error("", e);
        }
    }
}

package com.zl.integraterocketmq.consumer;

import com.zl.integraterocketmq.entity.OrderPaidEventTx;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
 * @Author: Tom
 * @Date: 2019/7/12 10:48
 */
@Slf4j
@Service
@RocketMQMessageListener(consumeMode = ConsumeMode.CONCURRENTLY, topic = "tx-text-topic",
        consumerGroup = "my-consumer_tx-text-topic", messageModel = MessageModel.CLUSTERING)
public class TxMQConsumer implements RocketMQListener<OrderPaidEventTx> {

    @Override
    public void onMessage(OrderPaidEventTx message) {
        log.info("消费端接收到事务消息:{}", message.toString());
    }
}

8.最后附上源码中的constant及util代码:

package com.zl.integraterocketmq.constant;
/**
 * @Author: Tom
 * @Date: 2019/7/11 16:19
 */
public class MessageDelayLevel {
    /**
     * 延迟1秒
     */
    public static final Integer TIME_1S = 1;
    /**
     * 延迟5秒
     */
    public static final Integer TIME_5S = 2;
    /**
     * 延迟10秒
     */
    public static final Integer TIME_10S = 3;
    /**
     * 延迟30秒
     */
    public static final Integer TIME_30S = 4;
    /**
     * 延迟一分钟
     */
    public static final Integer TIME_1M = 5;
    /**
     * 延迟两分钟
     */
    public static final Integer TIME_2M = 6;
    /**
     * 延迟三分钟
     */
    public static final Integer TIME_3M = 7;
    /**
     * 延迟4分钟
     */
    public static final Integer TIME_4M = 8;
    /**
     * 延迟五分钟
     */
    public static final Integer TIME_5M = 9;
    /**
     * 延迟六分钟
     */
    public static final Integer TIME_6M = 10;
    /**
     * 延迟七分钟
     */
    public static final Integer TIME_7M = 11;
    /**
     * 延迟八分钟
     */
    public static final Integer TIME_8M = 12;
    /**
     * 延迟九分钟
     */
    public static final Integer TIME_9M = 13;
    /**
     * 延迟10分钟
     */
    public static final Integer TIME_10M = 14;
    /**
     * 延迟二十分钟
     */
    public static final Integer TIME_20M = 15;
    /**
     * 延迟三十分钟
     */
    public static final Integer TIME_30M = 16;
    /**
     * 延迟一小时
     */
    public static final Integer TIME_1H = 17;
    /**
     * 延迟两小时
     */
    public static final Integer TIME_2H = 18;

}

package com.zl.integraterocketmq.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
/**
 * @Author: Tom
 * @Date: 2019/7/12 10:04
 */
@Slf4j
public class JsonUtil {

    private static ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
        mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
    }

    /**
     * 对象转json字符串
     *
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> String objectToJson(T obj) {
        if (obj == null) {
            return null;
        }
        try {
            return obj instanceof String ? (String) obj : mapper.writeValueAsString(obj);
        } catch (Exception e) {
            log.warn("Parse Object to Json error", e);
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 对象转格式化的json字符串
     *
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> String objectToJsonPretty(T obj) {
        if (obj == null) {
            return null;
        }
        try {
            return obj instanceof String ? (String) obj : mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (Exception e) {
            log.warn("Parse Object to Json error", e);
            e.printStackTrace();
            return null;
        }
    }

    /**
     * json转java对象
     *
     * @param src
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T jsonToObject(String src, Class<T> clazz) {
        if (StringUtils.isEmpty(src) || clazz == null) {
            return null;
        }
        try {
            return clazz.equals(String.class) ? (T) src : mapper.readValue(src, clazz);
        } catch (Exception e) {
            log.warn("Parse Json to Object error", e);
            e.printStackTrace();
            return null;
        }
    }

    /**
     * json转java对象或list、map
     *
     * @param src
     * @param typeReference
     * @param <T>
     * @return
     */
    public static <T> T jsonToObject(String src, TypeReference<T> typeReference) {
        if (StringUtils.isEmpty(src) || typeReference == null) {
            return null;
        }
        try {
            return (T) (typeReference.getType().equals(String.class) ? src : mapper.readValue(src, typeReference));
        } catch (Exception e) {
            log.warn("Parse Json to Object error", e);
            e.printStackTrace();
            return null;
        }
    }

    /**
     * json转java对象或list、map
     *
     * @param <T>
     * @param src
     * @return
     */
    public static <T> T jsonToObject(String src, Class<?> collectionClass, Class<?>... elementClasses) {
        JavaType javaType = mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
        try {
            return mapper.readValue(src, javaType);
        } catch (Exception e) {
            log.warn("Parse Json to Object error", e);
            e.printStackTrace();
            return null;
        }
    }
}

PS:因为最近项目使用,之前没有接触过,所以搜到比较好的能快速上手的demo,自己可以快速上手,可以分享给和我一样有需要的童鞋。

猜你喜欢

转载自blog.csdn.net/breakaway_01/article/details/107139668