一、Push模式和Pull模式的区别
Push模式:实时性强,占用系统资源,消费者关联的消息队列一有消息就会向消费者推送
Pull:实时性差,消息的拉取可控,消费者每隔一段时间去关联的消息队列中拉取消息
二、简单的消息发送
MQ中消息的发送有三种方式:同步,异步和单项
同步:
生产者发送消息时需要知道消费者是否消费成功才发送吓一跳消息,是阻塞的模型,可靠性高,但性能不好
异步:
生产者发送消息不需要知道消费者是否消费成功,发送完消息之后可以继续做自己的事儿,消费者是否消费成功是通过回调的方式告知生产者,可靠性和性能都比较高
单项:
生产者发送完消息之后就不管了,他不会等待结果的返回,也不会有结果返回,可靠性低,性能高
同步消息的实现(send或者syncSend,后者更加灵活,可以定义更多的配置,且有返回值,判断消息成功与否)
//这个是SpringBoot测试的写法
@RunWith(SpringRunner.class)
@SpringBootTest(classes = 启动类的字节码文件)
public class MQTest {
@Autowired
private RocketMQTemplate mqTemplate;
@Test
/**
* 同步消息send
*/
public void sendMessage(){
Message<String> message = MessageBuilder.withPayload("我是一个字符串消息").build();
//send(目的地的topic:目的地的tags,要发送的消息);
mqTemplate.send("topic-test:tags-test",message);
System.out.println("完成消息发送...");
}
/**
* 同步消息syncSend
*/
@Test
public void syncSendMessage(){
Message<String> message = MessageBuilder.withPayload("我是一个字符串消息").build();
/**如果你要将消息封装成对象可以通过以下方式
Message<你的消息的类型> message = MessageBuilder.withPayload(你的消息对象).build();
**/
//发送同步消息,2s发送不成功就超时
//syncSend(目的地的topic:目的地的tags,要发送的消息);
SendResult sendResult = mqTemplate.syncSend("topic-test:tags-test", message, 2000);
System.out.println(sendResult);
//判断发送结果状态
if(sendResult.getSendStatus() == SendStatus.SEND_OK){
System.out.println("发送成功");
}else{
System.out.println("发送失败");
}
}
}
异步消息的简单实现
/**
* 异步消息的简单实现
*/
@Test
public void asyncSendMessage(){
Message<String> message = MessageBuilder.withPayload("我是一个字符串消息").build();
/**如果你要将消息封装成对象可以通过以下方式
Message<你的消息的类型> message = MessageBuilder.withPayload(你的消息对象).build();
**/
//asyncSend(目的地的topic:目的地的tags,要发送的消息);
mqTemplate.asyncSend("topic-test:tags-test", message, new SendCallback() {
//成功的回调
@Override
public void onSuccess(SendResult sendResult) {
System.out.println(sendResult);
System.out.println("发送成功");
}
//失败的回调
@Override
public void onException(Throwable e) {
System.out.println("发送失败");
e.printStackTrace();
}
});
}
单项消息的简单实现
/**
* 单项消息的简单实现
*/
@Test
public void sendOneWayMessage(){
Message<String> message = MessageBuilder.withPayload("我是一个字符串消息").build();
/**如果你要将消息封装成对象可以通过以下方式
Message<你的消息的类型> message = MessageBuilder.withPayload(你的消息对象).build();
**/
//sendOneWay(目的地的topic:目的地的tags,要发送的消息);
mqTemplate.sendOneWay("topic-test:tags-test",message);
System.out.println("完成消息发送...");
}
三、简单的消息消费
Push模式:
当消息队列中有消息就推给消费者,基于RocketMQ的监听器,实现RocketMQListener接口(接口的泛型就是你要发送的消息的泛型,可以直接使用MessageExt,后续进行强转),重写其中的onMessage方法,在@RocketMQMessageListener注解中进行配置
@Component//交给Spring管理
@RocketMQMessageListener(
//消费者的组名,可以任意指定,唯一即可
consumerGroup = "consumer-group-xxx",
//主题,要和你要消费的消息的topic保持一致
topic = "topic-test",
//tags。要和你要消费的消息的tags保持一致
selectorExpression = "tags-test",
//消息消费模式:默认是CLUSTERING集群,还支持BROADCASTING广播,集群就是一对一,广播就是一对多(生产者-消费者)
messageModel = MessageModel.CLUSTERING)
//MessageExt:Message对象的子类
public class TestConsumer implements RocketMQListener<MessageExt> {
@Override
public void onMessage(MessageExt message) {
//这里拿到的消息 message.getBody 是byte[]格式。
if(message.getBody() == null ||message.getBody().length == 0)return;
//拿到消息:如果发送的消息是字符串,那么需要把byte[]转为字符串
String msg = new String(message.getBody(), StandardCharsets.UTF_8);
/**如果你传递到RocketMQ中的消息是自定义的对象,那么可以用以下方式读取
JSON.parseObject(msg, 你的消息的字节码对象);
**/
}
}
Pull模式:使用DefaultMQPullConsumer 的pull方法进行拉取
/**
* 主动拉取消息
*/
@Autowired
private DefaultMQPullConsumer pullConsumer;
@Test
public void pullMessage(){
try {
String orderTags ="tags-test";
//topic
String topic = "topic-test";
//订阅消息队列,指定topic
Set<MessageQueue> messageQueues = pullConsumer.fetchSubscribeMessageQueues(topic);
List result = new ArrayList<>();
for (MessageQueue messageQueue : messageQueues) {
//long offset = pullConsumer.searchOffset(messageQueue, System.currentTimeMillis());
//通过偏移量来获取消息
long offset = pullConsumer.fetchConsumeOffset(messageQueue, true);
//拉取消息 maxNums是每次最多拉取的消息条数
PullResult pullResult = pullConsumer.pull(messageQueue, orderTags, offset, 32);
//找到消息
if (pullResult != null && pullResult.getPullStatus().equals(PullStatus.FOUND)) {
List<MessageExt> messageExtList = pullResult.getMsgFoundList();
if (messageExtList == null || messageExtList.size() == 0) continue;
for (MessageExt messageExt : messageExtList) {
//拿到消息内容,转换为你的消息对象
String message = new String(messageExt.getBody(), StandardCharsets.UTF_8);
你的消息类型 yourMessage = JSON.parseObject(message, 你的消息类型的字节码对象);
//添加到结果列表
result.add(yourMessage);
//重要:修改消息的消费位置,如果位置不后移,消息会一直被消费
pullConsumer.updateConsumeOffset(messageQueue, pullResult.getNextBeginOffset());
}
}
}
} catch (Exception e) {
e.printStackTrace();
throw new GlobalException("MQ消息拉取失败");
}
}