前言
简单消息是Rocket MQ最基本的消息类型,特点就是… …没有特点。正因如此也就没有什么好讲述的内容,故该博文的讲述重点其实在于【发送方式】。
【注】本博文代码基于底层API实现以便于更好的展示流程,关于Spring Boot整合Rocket MQ请点击下方博文。
【附】博文:《Spring Boot(4):整合Rocket MQ》
一 发送方式
Rocket MQ共有三种发送方式:
- 同步发送
- 异步发送
- 单向发送
发送方式与消息类型没有直接关联。也就是说对于任何消息类型都会有三种发送方式,以后续会讲述的有序消息为例,分为:有序同步消息/有序异步消息/有序单向消息。开发者需要根据需求及应用场景选择的消息类型及发送方式。
/**
* 主方法
*
* @param args 数组
*/
public static void main(String[] args) {
try {
// 同步发送消息。
syncSendMessage();
// 异步发送消息。
asyncSendMessage();
// 单向发送消息。
oneWaySendMessage();
} catch (MQClientException | InterruptedException | RemotingException |
MQBrokerException | UnsupportedEncodingException e) {
e.printStackTrace();
}
}
二 同步发送(可靠)
同步消息具备回应机制【ACK】以确保消息被正确的从生产者发送至经纪人服务器。其最大的特点是会与线程中的其它任务同步执行。
/**
* 同步发送消息
*
* @throws MQClientException MQ客户端异常
* @throws RemotingException 远程异常
* @throws InterruptedException 终端异常
* @throws MQBrokerException 经纪人服务器异常
* @throws UnsupportedEncodingException 不支持编码异常
*/
public static void syncSendMessage() throws MQClientException, RemotingException,
InterruptedException, MQBrokerException, UnsupportedEncodingException {
// 实例化生产者/设置命名服务器地址/开启生产者。
DefaultMQProducer producer = new DefaultMQProducer("simple_producer");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
// 同步发送消息并接收回应。
byte[] body = "这是一条简单同步消息。".getBytes(RemotingHelper.DEFAULT_CHARSET);
Message message = new Message("simple", "sync", body);
System.out.println("开始发送简单同步消息......");
SendResult sendResult = producer.send(message);
System.out.println("简单同步消息发送结果:" + sendResult.getSendStatus());
System.out.println();
// 关闭生产者。
producer.shutdown();
}
三 异步发送(可靠)
异步发送同样具备回应机制,但与同步发送的不同在于其会与线程中的其它任务异步执行。也就是说其会开启一个新的专属线程用于发送并接收回应,如果业务场景要求较高的实时性,可以采用该种发送方式。
/**
* 发送异步消息
*
* @throws MQClientException MQ客户端异常
* @throws RemotingException 远程异常
* @throws InterruptedException 终端异常
* @throws UnsupportedEncodingException 不支持编码异常
*/
public static void asyncSendMessage() throws MQClientException, RemotingException,
InterruptedException, UnsupportedEncodingException {
// 实例化生产者/设置命名服务器地址/开启生产者。
DefaultMQProducer producer = new DefaultMQProducer("simple_producer");
producer.setNamesrvAddr("127.0.0.1:9876");
// 设置发送失败的重试次数,0表示不重试。
producer.setRetryTimesWhenSendAsyncFailed(5);
producer.start();
// 实例化计数器,用于防止异步线程在发送消息的过程中主线程关闭生产者。
CountDownLatch countDownLatch = new CountDownLatch(1);
// 异步发送消息并执行成功/失败逻辑。
byte[] body = "这是一条简单异步消息。".getBytes(RemotingHelper.DEFAULT_CHARSET);
Message message = new Message("simple", "async", body);
System.out.println("开始发送简单异步消息......");
producer.send(message, new SendCallback() {
/**
* 执行成功
* @param sendResult 发送结果
*/
@Override
public void onSuccess(SendResult sendResult) {
System.out.println("简单异步消息发送结果:" + sendResult.getSendStatus());
System.out.println();
countDownLatch.countDown();
}
/**
* 执行异常
* @param throwable 异常
*/
@Override
public void onException(Throwable throwable) {
System.out.println("简单异步消息发送异常。");
throwable.printStackTrace();
System.out.println();
countDownLatch.countDown();
}
});
countDownLatch.await();
// 关闭生产者。
producer.shutdown();
}
四 单向消息(不可靠)
单向消息不具备回应机制,也就是说其是不可靠的,对于不在意执行结果的任务可以采用该种发送方式。其与异步发送相同,与线程中的其它任务是异步执行的。
/**
* 单向发送消息
*
* @throws MQClientException MQ客户端异常
* @throws RemotingException 远程异常
* @throws InterruptedException 终端异常
* @throws UnsupportedEncodingException 不支持编码异常
*/
public static void oneWaySendMessage() throws MQClientException, RemotingException,
InterruptedException, UnsupportedEncodingException {
// 实例化生产者/设置命名服务器地址/开启生产者。
DefaultMQProducer producer = new DefaultMQProducer("simple_producer");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
// 单向发送消息。
byte[] body = "这是一条简单单向消息。".getBytes(RemotingHelper.DEFAULT_CHARSET);
Message message = new Message("simple", "one_way", body);
System.out.println("开始发送简单单向消息......");
producer.sendOneway(message);
System.out.println("别看了,简单单向消息没回应。");
System.out.println();
// 等待线程5秒钟,确保单向消息发送完全。
Thread.sleep(5000);
// 关闭生产者。
producer.shutdown();
}
消费
package simple;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;
import java.util.List;
/**
* @Author: 说淑人
* @Date: 2021/6/24 下午8:42
* @Description: 简单消费者
*/
public class SimpleConsumer {
/**
* 主方法
*
* @param args 数组
*/
public static void main(String[] args) {
try {
// 消费消息。
consumeMessage();
} catch (MQClientException e) {
e.printStackTrace();
}
}
/**
* 消费消息
*
* @throws MQClientException MQ客户端异常
*/
public static void consumeMessage() throws MQClientException {
// 实例化消费者(推模式)并设置命名服务器地址。
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("simple_consumer");
consumer.setNamesrvAddr("127.0.0.1:9876");
// 订阅主题,并设置接收一切标签。
consumer.subscribe("simple", "*");
// 向经纪人服务器注册并行消息监听器。
consumer.registerMessageListener(new MessageListenerConcurrently() {
/**
* 消费消息
* @param messageExts 消息列表
* @param consumeConcurrentlyContext 空间
* @return 消费并行状态
*/
@Override
public ConsumeConcurrentlyStatus consumeMessage(
List<MessageExt> messageExts,
ConsumeConcurrentlyContext consumeConcurrentlyContext) {
// 输出消息。
for (MessageExt messageExt : messageExts) {
System.out.println("主题:" + messageExt.getTopic());
System.out.println("标签:" + messageExt.getTags());
System.out.println("消息ID:" + messageExt.getMsgId());
String message = new String(messageExt.getBody());
System.out.println("消息内容:" + message);
System.out.println();
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
// 开启消费者。
consumer.start();
}
}