RocketMQ的API学习
目标是对rocketMq的生产和消费消息掌握,熟悉异步同步两种方式。
本篇基于RocketMQ集群开发,如需了解集群的搭建,可参考上一篇文章RocketMQ集群安装
项目构建
-
创建一个maven项目
-
引入依赖,建议和服务端RocketMQ版本保持一致
<dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-client</artifactId> <version>4.8.0</version> </dependency>
发送同步消息
定义公用常量类
MyRocketMqConstant中主要包括发送消息时需要传入的参数:
- NAME_SRV:启动的namesrv的地址,多节点用
;
分割 - SyncLearn:同步消息发送需要用到的生产者、消费者组,主题和tag
public interface MyRocketMqConstant {
/**
* 注册中心
*/
String NAME_SRV="192.168.15.14:9876;192.168.15.15:9876;192.168.15.16:9876";
/**
* 同步学习
*/
interface SyncLearn {
/**
* 生产者组
*/
String SYNC_PRODUCER_GROUP = "sync-producer-group";
/**
* 主题
*/
String SYNC_TOPIC = "sync-topic";
/**
* tag
*/
String SYNC_TAG = "sync-tag";
/**
* 消费者组
*/
String SYNC_CONSUMER_GROUP = "sync-consumer-group";
}
}
定义Producer
一个生产者从创建出来到发送消息到Broker需要经历以下步骤:
- 调用构造方法
DefaultMQProducer(final String producerGroup)
,创建一个组织为sync-producer-group的生产者 - 生产者对象调用
setNamesrvAddr(String namesrvAddr)
方法补充生产者将要注册的地址192.168.15.14:9876;192.168.15.15:9876;192.168.15.16:9876
,注意多个IP使用;
分割 - 生产者对象调用
start()
方法启动producer实例 - 调用
Message(String topic, String tags, byte[] body)
消息构造方法创建将要发送的消息;topic可以理解为消息的频道,生产者会把消息推送到指定的topic,消费者要消费此消息也需要指定相同的topic;tag可以理解为打在消息上的标签,消费者可利用 tag来进行过滤 - 生产者对象调用
send(Message msg)
使用同步方式将消息发送至Broker,同步操作能拿到SendResult类型的响应值 - 消息发送完毕时,生产者对象调用
shutdown()
方法关闭生产者
public class SyncProducer {
public static void main(String[] args) throws Exception{
// 1.实例化消息生产者,设置生产者组
DefaultMQProducer defaultMQProducer = new DefaultMQProducer(MyRocketMqConstant.SyncLearn.SYNC_PRODUCER_GROUP);
// 2.设置注册中心地址
defaultMQProducer.setNamesrvAddr(MyRocketMqConstant.NAME_SRV);
// 3.启动Producer实例
defaultMQProducer.start();
// 4.发送消息
for (int i = 0; i < 20; i++) {
String str = "Hello Rocket:" +i;
// 创建消息,并指定topic和tag
Message message = new Message(MyRocketMqConstant.SyncLearn.SYNC_TOPIC,
MyRocketMqConstant.SyncLearn.SYNC_TAG,
str.getBytes(StandardCharsets.UTF_8));
// 发送消息到broker
SendResult sendResult = defaultMQProducer.send(message);
// 观察响应
System.out.printf("生产者接收Broker的响应:%s%n",sendResult);
}
// 5.发送完毕,关闭Producer
defaultMQProducer.shutdown();
}
}
定义Consumer
消费者从Broker中消费消息需要经历以下步骤:
- 调用
DefaultMQPushConsumer(final String consumerGroup)
构造方法创建消费者对象,指定消费者的分组为sync-consumer-group
- 消费者对象调用
setNamesrvAddr(String namesrvAddr)
方法补充注册中心地址 - 消费者对象调用
subscribe(String topic, String subExpression)
方法订阅topic - 消费者对象调用
registerMessageListener(MessageListenerConcurrently messageListener)
方法注册一个消息监听器来处理消费的消息 - 消费者对象调用
start()
方法开始消费
public class Consumer {
public static void main(String[] args) throws Exception {
// 1.创建消费者
DefaultMQPushConsumer defaultMQPushConsumer = new DefaultMQPushConsumer(MyRocketMqConstant.SyncLearn.SYNC_CONSUMER_GROUP);
// 2.设置注册中心
defaultMQPushConsumer.setNamesrvAddr(MyRocketMqConstant.NAME_SRV);
// 3.订阅一个或多个Topic,以及Tag来过滤需要消费的消息
defaultMQPushConsumer.subscribe(MyRocketMqConstant.SyncLearn.SYNC_TOPIC,"*");
// 4.注册回调实现类来处理从broker拉取回来的消息
defaultMQPushConsumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
System.out.printf("%s 消费者接收到新消息:%s %n",Thread.currentThread().getName(),msgs);
// 标记该消息已经被消费了
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
// 5.开始消费
defaultMQPushConsumer.start();
System.out.printf("消费者开始..%n");
}
}
测试结果
-
运行生产者main方法
RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0). RocketMQLog:WARN Please initialize the logger system properly. 生产者接收Broker的响应:SendResult [sendStatus=SEND_OK, msgId=7F000001329018B4AAC24B3E61E80000, offsetMsgId=C0A80F0F00002A9F0000000000035CD6, messageQueue=MessageQueue [topic=sync-topic, brokerName=broker-a, queueId=2], queueOffset=11] #省略多余的响应信息..............................
-
运行消费者main方法
消费者开始.. ConsumeMessageThread_1 消费者接收到新消息:[MessageExt [brokerName=broker-a, queueId=2, storeSize=206, queueOffset=11, sysFlag=0, bornTimestamp=1618468779497, bornHost=/192.168.15.1:61006, storeTimestamp=1618468779476, storeHost=/192.168.15.15:10911, msgId=C0A80F0F00002A9F0000000000035CD6, commitLogOffset=220374, bodyCRC=855890706, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='sync-topic', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=12, CONSUME_START_TIME=1618468779510, UNIQ_KEY=7F000001329018B4AAC24B3E61E80000, CLUSTER=rocketmq-cluster, WAIT=true, TAGS=sync-tag}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 58, 48], transactionId='null'}]] #省略多余的响应信息..............................
发送异步消息
定义Producer
public class AsyncProducer {
public static void main(String[] args) throws Exception {
// 1.创建生产者
DefaultMQProducer defaultMQProducer = new DefaultMQProducer(MyRocketMqConstant.AsyncLearn.ASYNC_PRODUCER_GROUP);
// 2.设置注册中心
defaultMQProducer.setNamesrvAddr(MyRocketMqConstant.NAME_SRV);
// 3.启动生产者
defaultMQProducer.start();
defaultMQProducer.setRetryTimesWhenSendAsyncFailed(0);
// 定义消息总数
int messageCount = 100;
// 根据消息数量实例化倒计时计算器
final CountDownLatch2 countDownLatch2 = new CountDownLatch2(messageCount);
for (int i = 0; i < messageCount; i++) {
final int index = i;
String str = "hello world"+i;
// 4.创建消息,并指定topic和tag
Message message = new Message(MyRocketMqConstant.AsyncLearn.ASYNC_TOPIC,
MyRocketMqConstant.AsyncLearn.ASYNC_TAG,
str.getBytes(StandardCharsets.UTF_8));
// 5.异步发送消息到broker
defaultMQProducer.send(message, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.printf("%-10d OK %s %n",index,sendResult.getMsgId());
}
@Override
public void onException(Throwable e) {
System.out.printf("%-10d Exception %s %n",index,e);
e.printStackTrace();
}
});
}
// 6.等待5s
countDownLatch2.await(5, TimeUnit.SECONDS);
// 7.如果不再发送消息,关闭producer实例
defaultMQProducer.shutdown();
}
}
定义Consumer
可以复用发送同步消息的消费者,修改group和订阅的topic,topic要和上面的生产者发送消息的topic对应。
单向发送消息
定义Producer
public class OneWayProducer {
public static void main(String[] args) throws Exception {
// 1.实例化消息生产者producer
DefaultMQProducer defaultMQProducer = new DefaultMQProducer(MyRocketMqConstant.OneWayLearn.ONE_WAY_LEARN_PRODUCER_GROUP);
// 2.设置注册中心
defaultMQProducer.setNamesrvAddr(MyRocketMqConstant.NAME_SRV);
// 3.启动生产者
defaultMQProducer.start();
for (int i = 0; i < 100; i++) {
String str="Hello RocketMQ "+i;
// 4.创建消息,指定topic和tag
Message message = new Message(MyRocketMqConstant.OneWayLearn.ONE_WAY_LEARN_TOPIC,
MyRocketMqConstant.OneWayLearn.ONE_WAY_LEARN_TAG,
str.getBytes(StandardCharsets.UTF_8));
// 5.发送单项消息,没有任何返回结果
defaultMQProducer.sendOneway(message);
}
// 如果不再发送消息,关闭Producer实例
defaultMQProducer.shutdown();
}
}
定义Consumer
可以复用复用发送同步消息的消费者,修改group和订阅的topic,topic要和上面的生产者发送消息的topic对应。
总结
生产者发送异步消息、同步消息、单向消息的区别在于send方法。
- 发送同步消息:调用
send(Message msg)
,会有一个SendResult返回值;这种可靠性同步地发送方式使用的比较广泛,比如:重要的消息通知,短信通知。 - 发送异步消息:调用
send(Message msg,SendCallback sendCallback)
,无返回值;异步消息通常用在对响应时间敏感的业务场景,即发送端不能容忍长时间地等待Broker的响应。 - 发送单向消息:调用
sendOneway(Message msg)
,无返回值;这种方式主要用在不特别关心发送结果的场景,例如日志发送。