RocketMQ单机版详解,事务消息、顺序消息、转换消息、可回复消息等

一、说明

1-1、安装和快速测试

1-2、下面的代码使用的版本

  • SpringBoot   2.2.0.RELEASE
  • RocketMQ   4.6.1
  • Rocketmq-spring-boot-starter   2.2.0

1-3、相关文档


二、RocketMQ组件

2-1、封装RocketMQTemplate

为了使用的方便,我们把这RocketMQTemplate进行静态化

import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * rocketMQ生产者
 */
@Component
public class ProducerUtils {
    public static RocketMQTemplate rocketMQTemplate;

    @Autowired
    public ProducerUtils(RocketMQTemplate rocketMQTemplate) {
        ProducerUtils.rocketMQTemplate = rocketMQTemplate;
    }
}

2-2、生产者(Producer)

下面发消息的时候一起用


2-3、消费者(consumer)

消费者可以主动消费(pull),也可以被动消费(push)

如果我们的消费者压力不大的话,可以选择被动消费,这样消息没有延迟,而且处理起来简单。

2-3-1、push消费

也就是当有消息来的时候,broker会把消息推送给我们消费者

2-3-1-1、获取不需要返回值的消息
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;


@Service
@RocketMQMessageListener(consumerGroup = "my-consumer_sync-topic_two", topic = "topic")
public class Consumer implements RocketMQListener<MessageExt> {

    public void onMessage(MessageExt message) {
        // 1、这个message里面包含了很多消息,具体可以点进去查看
        System.out.println(message);
        // 2、这个body才是生产者发送的具体消息
        System.out.println(new String(message.getBody()));
    }
}
2-3-1-2、获取需要返回值的消息

RocketMQReplyListener的第二个泛型就是返回值类型

import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQReplyListener;
import org.springframework.stereotype.Service;


@Service
@RocketMQMessageListener(consumerGroup = "my-consumer_sync-topic_two", topic = "topic")
public class Consumer implements RocketMQReplyListener<MessageExt,String> {

    public String onMessage(MessageExt message) {
        // 1、这个message里面包含了很多消息,具体可以点进去查看
        System.out.println(message);
        // 2、这个body才是生产者发送的具体消息
        System.out.println(new String(message.getBody()));

        return "返回值";
    }
}

2-3-2、pull消费

2-3-2-1、默认的消费者
@GetMapping("/test2")
public String fun2() {
    List<MessageExt> receive = ProducerUtils.rocketMQTemplate.receive(MessageExt.class);
    for (MessageExt item : receive){
        System.out.println(item);
    }
    return "成功";
}
  • 泛型传递 MessageExt 就获取全部的消息信息
  • 泛型传递消息类型,比如String,那么就只返回我们生产者发送的消息了

eg:如果我们改成这样的 List receive = ProducerUtils.rocketMQTemplate.receive(String.class); 那么打印结果就是 message

2-3-2-2、自定义消费者

可以对自定义的消费者进行设置,比如线程池的个数、消费的topic等

@Component
public class ProducerUtils {

    public static RocketMQTemplate rocketMQTemplate;

    @Autowired
    public ProducerUtils(RocketMQTemplate rocketMQTemplate) throws MQClientException {
        // 设置默认的消费者  主要要自定义消费者组名称,不然重复了
        DefaultLitePullConsumer consumer = new DefaultLitePullConsumer("MY_CONSUMER");
	// 自定义消费的topic
        consumer.subscribe("topicA","*");
        rocketMQTemplate.setConsumer(consumer);
        // 开启消费者
        rocketMQTemplate.getConsumer().start();
        ProducerUtils.rocketMQTemplate = rocketMQTemplate;
    }
}
2-3-2-3、其它

主动消费的话有两种方式

  • 一种是写定时任务,定时去执行我们的消费方法
  • 另一种是轮询,我们写一个 while(true) 反复去获取最新的消息

轮询的方式还是相对好一些,可以及时的去消费。我们可以开一个线程池去轮询,每次没有获取到最新的消息可以让线程休息一段时间。


2-3、发送消息

2-3-1、普通消息

携带topic的普通消息

Message<String> message = MessageBuilder.withPayload("message").build();
ProducerUtils.rocketMQTemplate.send("topic",message);

不携带topic的普通消息(需要在创建生产者的时候设置默认的topic不然会报错)

ProducerUtils.rocketMQTemplate.send(message);
2-3-2、可接受回复的消息

如标题所示此类消息,可以接受消费者返回的数据。发送的方法为xxxxReceive

参数名含义
destinationtopic名称
payload消息内容
type返回的数据类型
message消息内容
timeout超时时间,大于这个时间没有返回数据就超时,默认3000ms
delayLevel延迟消息 DelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h ,0=0s,1=1s,2=5s…
hashKey通过源码我们可以查看这个是用来选择发送队列的,如果hashKey一样那么队列也一样
rocketMQLocalRequestCallback自定义接受回调和异常处理

知道了上面的参数含义,调用起来就很简单了,这里写一个自定义回调的demo

import org.apache.rocketmq.spring.core.RocketMQLocalRequestCallback;

public class RequestCallback implements RocketMQLocalRequestCallback<String> {
    public void onSuccess(String s) {
        System.out.println("啊!我接收到了消息 : " + s);
    }

    public void onException(Throwable throwable) {
        String message = throwable.getMessage();
        System.out.println("啊!我出现了异常 " + message);
    }
}

RequestCallback requestCallback = new RequestCallback();
ProducerUtils.rocketMQTemplate.sendAndReceive("topic", "message",requestCallback);
2-3-3、单向消息

这种方式主要用在不特别关心发送结果的场景,例如日志发送。

ProducerUtils.rocketMQTemplate.sendOneWay("topic","message");
2-3-4、单向顺序消息

从上面我们知道指定hashKey就指定了一个队列发送,而队列的消费是顺序的,所以这样就是顺序消息了

ProducerUtils.rocketMQTemplate.sendOneWayOrderly("topic","message","1");
2-3-5、同步消息
SendResult topic = ProducerUtils.rocketMQTemplate.syncSend("topic", "sync-message");
System.out.println(topic);

使用 syncSendOrderly 来发送顺序的同步消息。

2-3-6、异步消息

异步消息返回的结果和同步一样(SendResult),只是不需要及时返回,我们需要实现SendCallback接口

import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;

public class RequestCallback implements SendCallback {

    public void onSuccess(SendResult sendResult) {
        System.out.println("异步返回结果:" + sendResult);
    }

    public void onException(Throwable throwable) {
        System.out.println("啊、我异常了 " + throwable.getMessage());
    }
}


RequestCallback requestCallback = new RequestCallback();
ProducerUtils.rocketMQTemplate.asyncSend("topic","async-miss", requestCallback);

当然我们也可以使用sendOneWayOrderly来发送顺序消息,一样的加上hashKey就可以。

2-3-7、转换消息

可以理解成某些消息我们需要经过特殊的处理然后再发给消费者。

Map<String, Object> headers 可以理解成特殊处理时候的配置文件。

MessagePostProcessor 特殊处理的处理器

import org.springframework.messaging.Message;
import org.springframework.messaging.core.MessagePostProcessor;
import org.springframework.messaging.support.MessageBuilder;

public class MessageHandler implements MessagePostProcessor {
    public Message<?> postProcessMessage(Message<?> message) {
        Object o = message.getHeaders().get("123");
        Message<String> message1 = MessageBuilder.withPayload(message.getPayload() + o.toString()).build();
        // 这个message1 才是最终发给消费者的
        return message1;
    }
}


MessageHandler messageHandler = new MessageHandler();
Map<String, Object> map = new HashMap<String, Object>();
map.put("123","12345");
ProducerUtils.rocketMQTemplate.convertAndSend("topic","wa messa",map,messageHandler);
2-3-8、事务消息

我们知道事务是保持一致性的,MQ事务,很自然的就想到了是保证生产者发送成功,消费者消费成功吗?其实不然

RocketMQ事务消息是保持你的业务代码和发消息的一致性

当我们发送事务消息到了broker(注意这时候消费者是看不到这条消息的),这时候broker会去请求executeLocalTransaction方法执行我们本地的事务代码

  • 返回commit,消费者就可以正常消费了
  • 返回rollback,消息就被删除了,不会被消费
  • 返回unknown,消息不会被消费,也不会被删除

如果你返回了unknown或者null,这时候broker就回去访问你的checkLocalTransaction方法,进行检查消息你本地的事务是成功了还是失败了,我们的checkLocalTransaction方法也是返回上面三个状态,操作也是一样的。

发送事务消息

Message<String> message = MessageBuilder.withPayload("message").build();
TransactionSendResult transactionSendResult = ProducerUtils.rocketMQTemplate.sendMessageInTransaction("topic", message, 123);

事务监听器

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;

@RocketMQTransactionListener
public class Tran implements RocketMQLocalTransactionListener {
    public RocketMQLocalTransactionState executeLocalTransaction(Message message, Object o) {

        // 1、执行你的事务
        System.out.println(message);
        System.out.println(o);
        // 2、返回状态码给MQ
        return RocketMQLocalTransactionState.UNKNOWN;
    }

    public RocketMQLocalTransactionState checkLocalTransaction(Message message) {
        // 检查本地事务执行的结果
        System.out.println(message);
        return RocketMQLocalTransactionState.COMMIT;
    }
}

在这里插入图片描述


三、源码

关注微信公众号回复:rocketmq2.0

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值