目录
🎂除了上面提到的优化,我们还可以进一步优化RocketMQ的使用,具体如下:
🎂前言:
前面写了rabbitMq的消息队列,今天补充一下RocketMQ
🎂引入 Maven 依赖:
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.9.0</version>
</dependency>
🎂发送消息:
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import java.nio.charset.StandardCharsets;
public class AsyncProducer {
public static void main(String[] args) {
DefaultMQProducer producer = new DefaultMQProducer("producer-group");
producer.setNamesrvAddr("localhost:9876");
try {
producer.start();
for (int i = 0; i < 10; i++) {
Message message = new Message("topic", "tag", ("消息" + i).getBytes(StandardCharsets.UTF_8));
producer.send(message, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.println("消息发送成功:" + sendResult);
}
@Override
public void onException(Throwable throwable) {
System.out.println("消息发送失败:" + throwable.getMessage());
}
});
}
Thread.sleep(10000); // 等待消息发送完成
} catch (MQClientException | InterruptedException e) {
e.printStackTrace();
} finally {
producer.shutdown();
}
}
}
🎂接收消息:
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import java.util.List;
public class AsyncConsumer {
public static void main(String[] args) {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer-group");
consumer.setNamesrvAddr("localhost:9876");
try {
consumer.subscribe("topic", "tag");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
System.out.println("消息接收成功:" + list);
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
Thread.sleep(10000); // 等待消息接收完成
} catch (Exception e) {
e.printStackTrace();
} finally {
consumer.shutdown();
}
}
}
在上面的代码中,异步通信是通过设置
SendCallback
回调函数来实现的。在发送消息时,我们使用producer.send()
方法并设置回调函数SendCallback
,当消息发送成功或失败时,程序会回调相应的方法。消息发送成功时,
SendCallback.onSuccess()
方法会被调用,我们可以在这里处理发送成功的逻辑,比如打印日志。而当消息发送失败时,SendCallback.onException()
方法会被调用,我们可以在这里处理发送失败的逻辑,比如打印错误信息。由于消息的发送和接收都是异步的,因此我们需要等待一段时间,让消息发送和接收完成。在示例代码中,我们使用
Thread.sleep()
方法进行了等待,但实际应用中,这种方式并不可取,因为无法保证等待时间是否准确。正确的方式是使用其他的方式来进行等待,比如使用计数器或者等待条件的方式。需要注意的是,如果在发送消息时设置了回调函数
SendCallback
,那么消息将会异步发送,即程序不会等待消息发送完成就继续执行后续逻辑。因此,在异步通信中,我们需要仔细考虑消息发送和接收的顺序,以保证消息的正确性。
🎂除了上面提到的优化,我们还可以进一步优化RocketMQ的使用,具体如下:
使用RocketMQ的事务消息功能,确保消息的可靠性和一致性。
使用RocketMQ的延迟消息功能,实现定时任务和延迟消息的发送。
使用RocketMQ的顺序消息功能,确保消息的顺序性。
使用RocketMQ的批量消息功能,提高消息的发送效率。
🎂生产者类RocketMQProducer.java
:
public class RocketMQProducer {
private final String namesrvAddr;
private final String group;
private final String topic;
public RocketMQProducer(String namesrvAddr, String group, String topic) {
this.namesrvAddr = namesrvAddr;
this.group = group;
this.topic = topic;
}
public void send(String message) throws Exception {
try (TransactionMQProducer producer = new TransactionMQProducer(group)) {
producer.setNamesrvAddr(namesrvAddr);
producer.setTransactionListener(new TransactionListenerImpl());
producer.start();
Message msg = new Message(topic, "", message.getBytes(StandardCharsets.UTF_8));
TransactionSendResult result = producer.sendMessageInTransaction(msg, null);
System.out.printf("消息发送结果:%s%n", result);
}
}
public void sendDelay(String message, int delayTime) throws Exception {
try (DefaultMQProducer producer = new DefaultMQProducer(group)) {
producer.setNamesrvAddr(namesrvAddr);
producer.start();
Message msg = new Message(topic, "", message.getBytes(StandardCharsets.UTF_8));
msg.setDelayTimeLevel(delayTime);
SendResult result = producer.send(msg);
System.out.printf("消息发送结果:%s%n", result);
}
}
public void sendOrderly(List<String> messages) throws Exception {
try (DefaultMQProducer producer = new DefaultMQProducer(group)) {
producer.setNamesrvAddr(namesrvAddr);
producer.start();
for (String message : messages) {
Message msg = new Message(topic, "", message.getBytes(StandardCharsets.UTF_8));
SendResult result = producer.send(msg, new MessageQueueSelector() {
@Override
public MessageQueue select(List<MessageQueue> list, Message message, Object o) {
int index = (int) o % list.size();
return list.get(index);
}
}, messages.indexOf(message));
System.out.printf("消息发送结果:%s%n", result);
}
}
}
public void sendBatch(List<String> messages) throws Exception {
try (DefaultMQProducer producer = new DefaultMQProducer(group)) {
producer.setNamesrvAddr(namesrvAddr);
producer.start();
List<Message> msgList = new ArrayList<>();
for (String message : messages) {
Message msg = new Message(topic, "", message.getBytes(StandardCharsets.UTF_8));
msgList.add(msg);
}
SendResult result = producer.send(msgList);
System.out.printf("消息发送结果:%s%n", result);
}
}
static class TransactionListenerImpl implements TransactionListener {
private final Random random = new Random();
@Override
public LocalTransactionState executeLocalTransaction(Message message, Object o) {
int status = random.nextInt(3);
switch (status) {
case 0:
return LocalTransactionState.UNKNOW;
case 1:
return LocalTransactionState.COMMIT_MESSAGE;
case 2:
return LocalTransactionState.ROLLBACK_MESSAGE;
default:
return LocalTransactionState.UNKNOW;
}
}
@Override
public LocalTransactionState checkLocalTransaction(MessageExt messageExt) {
return LocalTransactionState.COMMIT_MESSAGE;
}
}
}
🎂讲解:
RocketMQProducer
类是RocketMQ的生产者类,用于发送消息。send
方法用于发送事务消息,首先创建一个TransactionMQProducer
对象,设置RocketMQ的Namesrv地址和事务监听器,然后启动生产者。接着创建一个消息对象Message
,设置消息的主题、标签和内容,调用sendMessageInTransaction
方法发送消息,并返回事务消息的发送结果。sendDelay
方法用于发送延迟消息,首先创建一个DefaultMQProducer
对象,设置RocketMQ的Namesrv地址,然后启动生产者。接着创建一个消息对象Message
,设置消息的主题、标签、内容和延迟时间,调用send
方法发送消息,并返回延迟消息的发送结果。sendOrderly
方法用于发送顺序消息,首先创建一个DefaultMQProducer
对象,设置RocketMQ的Namesrv地址,然后启动生产者。接着遍历消息列表,创建一个消息对象Message
,设置消息的主题、标签和内容,调用send
方法发送消息,并返回顺序消息的发送结果。sendBatch
方法用于发送批量消息,首先创建一个DefaultMQProducer
对象,设置RocketMQ的Namesrv地址,然后启动生产者。接着遍历消息列表,创建一个消息对象Message
,设置消息的主题、标签和内容,并将消息添加到消息列表中。最后调用send
方法发送消息,并返回批量消息的发送结果。TransactionListenerImpl
是事务监听器的实现类,用于处理事务消息的本地事务和事务状态检查。在executeLocalTransaction
方法中,我们随机生成一个事务状态,模拟本地事务的执行结果。在checkLocalTransaction
方法中,我们直接返回COMMIT_MESSAGE
,表示事务已经提交。- 在
RocketMQProducer
类中,我们使用了try-with-resources
语句来自动关闭生产者对象,避免了资源泄漏的问题。
🎂消费者类RocketMQConsumer.java
:
public class RocketMQConsumer {
private final String namesrvAddr;
private final String group;
private final String topic;
private final String tag;
public RocketMQConsumer(String namesrvAddr, String group, String topic, String tag) {
this.namesrvAddr = namesrvAddr;
this.group = group;
this.topic = topic;
this.tag = tag;
}
public void receive() throws Exception {
try (DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(group)) {
consumer.setNamesrvAddr(namesrvAddr);
consumer.subscribe(topic, tag);
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
for (MessageExt message : list) {
System.out.printf("接收到消息:%s%n", new String(message.getBody(), StandardCharsets.UTF_8));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
System.out.println("消费者已启动");
Thread.sleep(Long.MAX_VALUE);
}
}
public void receiveOrderly() throws Exception {
try (DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(group)) {
consumer.setNamesrvAddr(namesrvAddr);
consumer.subscribe(topic, tag);
consumer.registerMessageListener(new MessageListenerOrderly() {
@Override
public ConsumeOrderlyStatus consumeMessage(List<MessageExt> list, ConsumeOrderlyContext consumeOrderlyContext) {
for (MessageExt message : list) {
System.out.printf("接收到消息:%s%n", new String(message.getBody(), StandardCharsets.UTF_8));
}
return ConsumeOrderlyStatus.SUCCESS;
}
});
consumer.start();
System.out.println("消费者已启动");
Thread.sleep(Long.MAX_VALUE);
}
}
}
🎂讲解:
RocketMQConsumer
类是RocketMQ的消费者类,用于接收消息。receive
方法用于接收普通消息,首先创建一个DefaultMQPushConsumer
对象,设置RocketMQ的Namesrv地址和消费者组,然后订阅主题和标签。接着注册一个消息监听器MessageListenerConcurrently
,在consumeMessage
方法中处理接收到的消息,并返回消费结果。最后启动消费者,并让线程休眠,等待消息的到来。receiveOrderly
方法用于接收顺序消息,首先创建一个DefaultMQPushConsumer
对象,设置RocketMQ的Namesrv地址和消费者组,然后订阅主题和标签。接着注册一个消息监听器MessageListenerOrderly
,在consumeMessage
方法中处理接收到的消息,并返回消费结果。最后启动消费者,并让线程休眠,等待消息的到来。
🎂测试类RocketMQTest.java
:
public class RocketMQTest {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
try (InputStream in = RocketMQTest.class.getClassLoader().getResourceAsStream("application.properties")) {
props.load(in);
}
String namesrvAddr = props.getProperty("rocketmq.namesrvAddr");
String producerGroup = props.getProperty("rocketmq.producer.group");
String consumerGroup = props.getProperty("rocketmq.consumer.group");
String topic = props.getProperty("rocketmq.topic");
String tag = props.getProperty("rocketmq.tag");
RocketMQProducer producer = new RocketMQProducer(namesrvAddr, producerGroup, topic);
producer.send("Hello, RocketMQ!");
producer.sendDelay("Hello, RocketMQ! (delayed)", 3);
producer.sendOrderly(Arrays.asList("A", "B", "C", "D", "E"));
producer.sendBatch(Arrays.asList("1", "2", "3", "4", "5"));
RocketMQConsumer consumer = new RocketMQConsumer(namesrvAddr, consumerGroup, topic, tag);
consumer.receive();
consumer.receiveOrderly();
}
}
- 在
main
函数中,我们首先读取配置文件中的RocketMQ相关配置,然后创建生产者和消费者对象,并调用它们的方法来发送和接收消息。- 在配置文件中,我们设置了RocketMQ的Namesrv地址、生产者组、消费者组、主题和标签。这些配置项可以根据实际情况进行修改。
- rocketmq.namesrvAddr=localhost:9876
rocketmq.producer.group=producer_group
rocketmq.consumer.group=consumer_group
rocketmq.topic=test_topic
rocketmq.tag=test_tag