1 概述
RocketMQ(三):消息类型(普通、定时、顺序和事务消息)
上面5篇内容根据Apache RocketMQ官网,学习了理论方面的知识,内容中穿插的代码也仅仅配合基础知识。从本篇开始,真正通过代码实现上面的功能。
2 准备工作
1、部署RocketMQ,建议在Linux环境部署使用。
2、版本:jdk-8u401-linux-x64 、rocketmq-all-5.1.3-bin-release、RocketMQ Dashboard。
3、如何部署请自行百度或参考官网,目前学习阶段部署单机版即可。
3 创建生产者公共方法
准备工作,需要提前在RocketMQ Dashboard 新建一个主题即可。
package com.jay.demo01;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.apis.ClientConfiguration;
import org.apache.rocketmq.client.apis.ClientException;
import org.apache.rocketmq.client.apis.ClientServiceProvider;
import org.apache.rocketmq.client.apis.producer.Producer;
import org.apache.rocketmq.client.apis.producer.ProducerBuilder;
import org.apache.rocketmq.client.apis.producer.TransactionChecker;
import java.time.Duration;
@Slf4j
public class ProducerSingleton {
private static Producer PRODUCER;
private static Producer TRANSACTIONAL_PRODUCER;
private static final String ENDPOINT = "xxx.xxx.xxx.xxx:8081";
public ProducerSingleton() {
}
private static Producer buildProducer(TransactionChecker checker,String ... topic) throws ClientException {
ClientServiceProvider provider = ClientServiceProvider.loadService();
ClientConfiguration clientConfiguration = ClientConfiguration.newBuilder().setEndpoints(ENDPOINT)
.setRequestTimeout(Duration.ofSeconds(10)).build();
ProducerBuilder producerBuilder = provider.newProducerBuilder()
.setTopics(topic)
.setMaxAttempts(3)
.setClientConfiguration(clientConfiguration);
if(checker != null){
producerBuilder.setTransactionChecker(checker);
}
Producer producer = producerBuilder.build();
log.info("producer 创建成功[{}]",producer.getClass());
return producerBuilder.build();
}
public static Producer getInstance(String ... topic) throws ClientException {
if(null == PRODUCER){
synchronized (ProducerSingleton.class){
if(null == PRODUCER){
PRODUCER = buildProducer(null,topic);
}
}
}
return PRODUCER;
}
public static Producer getTransactionalProducer(TransactionChecker checker,String ... topic) throws ClientException {
if(null == TRANSACTIONAL_PRODUCER){
synchronized (ProducerSingleton.class){
if(null == TRANSACTIONAL_PRODUCER){
TRANSACTIONAL_PRODUCER = buildProducer(checker,topic);
}
}
}
return TRANSACTIONAL_PRODUCER;
}
public static void main(String[] args) throws ClientException {
Producer producer = ProducerSingleton.getInstance("topic001");
}
}
运行结果
4 使用PushConsumer和SimpleConsumer消费消息
准备工作:创建主题、消费者组、标签
package com.jay.demo01;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.apis.ClientConfiguration;
import org.apache.rocketmq.client.apis.ClientException;
import org.apache.rocketmq.client.apis.ClientServiceProvider;
import org.apache.rocketmq.client.apis.consumer.*;
import org.apache.rocketmq.client.apis.message.MessageId;
import org.apache.rocketmq.client.apis.message.MessageView;
import java.io.IOException;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
@Slf4j
public class PushConsumerAndSimpleConsumerTest {
//接入点
private static final String ENDPOINT = "XXX.XXX.XXX.XXX:8081";
//消费者组名
private static final String GROUPNAME = "groupName01";
//Tag标签
private static final String TAG = "TAG01";
//主题
private static final String TOPIC = "topic001";
public static void main(String[] args) throws ClientException, IOException, InterruptedException {
final ClientServiceProvider provider = ClientServiceProvider.loadService();
//测试PushConsumer
//testPushConsumer(provider);
//测试SimpleConsumer
testSimpleConsumer(provider);
}
public static void testPushConsumer(ClientServiceProvider provider)throws InterruptedException, IOException, ClientException{
//定义ClientConfiguration,设置接入点
ClientConfiguration clientConfiguration = ClientConfiguration.newBuilder()
.setEndpoints(ENDPOINT)
.build();
//定义过滤表达式
FilterExpression filterExpression = new FilterExpression(TAG, FilterExpressionType.TAG);
//定义PushConsumer
log.info("pushConsumer 开始接收信息");
PushConsumer pushConsumer = provider.newPushConsumerBuilder()
//设置配置信息
.setClientConfiguration(clientConfiguration)
//设置消费者组
.setConsumerGroup(GROUPNAME)
//设置主题表达式
.setSubscriptionExpressions(Collections.singletonMap(TOPIC,filterExpression))
//设置消息监听器
.setMessageListener(messageView -> {
log.info("PushConsumer message = {}", messageView);
return ConsumeResult.SUCCESS;
})
.build();
Thread.sleep(Long.MAX_VALUE);
pushConsumer.close();
}
public static void testSimpleConsumer(ClientServiceProvider provider) throws ClientException {
//1 客户端配置接入点
ClientConfiguration clientConfiguration = ClientConfiguration.newBuilder()
.setEndpoints(ENDPOINT)
.build();
// 2 配置 Tag标签过滤表达式
FilterExpression filterExpression = new FilterExpression(TAG, FilterExpressionType.TAG);
//3 设置请求时间
Duration duration = Duration.ofSeconds(30);
//4 创建SimpleConsumer
SimpleConsumer simpleConsumer = provider.newSimpleConsumerBuilder()
.setClientConfiguration(clientConfiguration)
//配置消费者组
.setConsumerGroup(GROUPNAME)
//配置等待时间
.setAwaitDuration(duration)
//为消费者设置订阅属性,包括主题和标签
.setSubscriptionExpressions(Collections.singletonMap(TOPIC, filterExpression))
.build();
//5 设置最多消息数量
int maxMessageNum = 16;
// 6 设置不可见时间
Duration invisibleDuration = Duration.ofSeconds(15);
//7 接收信息
do{
log.info("simpleConsumer 开始接收信息");
final List<MessageView> messageViewList = simpleConsumer.receive(maxMessageNum,invisibleDuration);
log.info("simpleConsumer 接收{} 消息",messageViewList.size());
for(MessageView messageView : messageViewList){
final MessageId messageId = messageView.getMessageId();
try {
simpleConsumer.ack(messageView);
log.info("消息被成功消费,messageId = {}",messageId);
}catch (Throwable t){
log.error("消息消费失败,messageId = {}",messageId,t);
}
}
}while (true);
}
}
testSimpleConsumer()运行结果:
testPushConsumer()运行结果
5 发送/接收普通消息
5.1 生产者发送普通同步消息
package com.jay.demo01;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.apis.ClientException;
import org.apache.rocketmq.client.apis.ClientServiceProvider;
import org.apache.rocketmq.client.apis.message.Message;
import org.apache.rocketmq.client.apis.producer.Producer;
import org.apache.rocketmq.client.apis.producer.SendReceipt;
import org.checkerframework.checker.units.qual.C;
import java.nio.charset.StandardCharsets;
@Slf4j
public class MessageTest {
//接入点
private static final String ENDPOINT = "xxx.xxx.xxx.xxx:8081";
//消费者组名
private static final String GROUPNAME = "groupName01";
//Tag标签
private static final String TAG = "TAG01";
//主题
private static final String TOPIC = "topic001";
public static void main(String[] args) throws ClientException {
final ClientServiceProvider provider = ClientServiceProvider.loadService();
normalMessageTest(provider);
}
public static void normalMessageTest(ClientServiceProvider provider) throws ClientException {
final Producer producer = ProducerSingleton.getInstance(TOPIC);
byte[] messageBody = "This is a normal message for Apache RocketMQ".getBytes(StandardCharsets.UTF_8);
Message message = provider.newMessageBuilder()
//设置主题
.setTopic(TOPIC)
//设置标签
.setTag(TAG)
//设置唯一索引键
.setKeys("001")
//设置消息体
.setBody(messageBody)
.build();
try {
final SendReceipt sendReceipt = producer.send(message);
log.info("发送消息成功, messageId={}", sendReceipt.getMessageId());
}catch (Throwable t){
log.error("发送消息失败", t);
}
}
}
运行结果
使用PushConsumer消费普通消息,运行结果
使用SimpleConsumer消费消息,运行结果
5.2 生产者发送普通异步消息
public static void normalMessageAsyncTest(ClientServiceProvider provider) throws ClientException {
final Producer producer = ProducerSingleton.getInstance(TOPIC);
for (int i = 0; i < 20; i++) {
byte[] messageBody = "This is a normal message for Apache RocketMQ".getBytes(StandardCharsets.UTF_8);
Message message = provider.newMessageBuilder()
//设置主题
.setTopic(TOPIC)
//设置标签
.setTag(TAG)
//设置唯一索引键
.setKeys("001")
//设置消息体
.setBody(messageBody)
.build();
CompletableFuture<SendReceipt> future = producer.sendAsync(message);
ExecutorService threadPool = Executors.newFixedThreadPool(5);
future.whenCompleteAsync((sendReceipt,throwable) ->{
if(null != throwable){
log.info("消息发送失败");
}
log.info("消息发送成功,messageId = {}", sendReceipt.getMessageId());
},threadPool);
}
}
生产者发送异步消息运行结果
消费者消费消息运行结果