生产者应用程序
pom.xml
:添加 RocketMQ 和 Redisson 依赖。
<dependencies>
<!-- RocketMQ -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.9.3</version>
</dependency>
<!-- Redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.0</version>
</dependency>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
RocketmqProducerManager.java
:生产者管理类。
package com.kabai;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class RocketmqProducerManager {
private static final int MAX_RETRY_TIMES = 3; // 最大重试次数
private DefaultMQProducer producer;
public RocketmqProducerManager(@Value("${rocketmq.namesrvAddr}") String namesrvAddr,
@Value("${rocketmq.producer.groupName}") String producerGroup) throws MQClientException {
// 创建一个生产者实例,指定生产者组名
producer = new DefaultMQProducer(producerGroup);
producer.setNamesrvAddr(namesrvAddr);
producer.start(); // 启动生产者实例
}
public void sendSuccess(String topic, String tag, String messageBody) {
Message message = new Message(topic, tag, messageBody.getBytes());
sendWithRetry(message);
}
private void sendWithRetry(Message message) {
int attempt = 0;
boolean success = false;
while (attempt < MAX_RETRY_TIMES && !success) {
attempt++;
try {
SendResult sendResult = producer.send(message);
// 检查发送状态
if (sendResult.getSendStatus() == SendStatus.SEND_OK) {
System.out.println("Message sent successfully: " + sendResult);
success = true;
} else {
System.err.println("Message sending failed: " + sendResult);
}
} catch (MQClientException | RemotingException | MQBrokerException | InterruptedException e) {
System.err.println("Message sending failed on attempt " + attempt + ": " + e);
e.printStackTrace();
}
// 如果未成功,等待一段时间后重试
if (!success) {
try {
Thread.sleep(1000); // 等待1秒后重试
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
if (!success) {
// 发送失败后进行必要的补偿措施,比如记录到数据库、日志或报警
System.err.println("Failed to send message after " + MAX_RETRY_TIMES + " attempts.");
}
}
public void shutdownProducer() {
producer.shutdown(); // 关闭生产者实例
}
}
- 生产者的 Spring Boot 应用程序主类。
package com.kabai;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RocketmqProducerApplication implements CommandLineRunner {
@Autowired
private RocketmqProducerManager rocketmqProducerManager;
public static void main(String[] args) {
SpringApplication.run(RocketmqProducerApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
rocketmqProducerManager.sendSuccess("TopicTest", "TagA", "Hello RocketMQ, ensuring delivery!");
rocketmqProducerManager.shutdownProducer();
}
}
application.properties
:配置文件。
rocketmq.namesrvAddr=127.0.0.1:9876
rocketmq.producer.groupName=ReliableProducerGroup
消费者应用程序
pom.xml
:添加 RocketMQ 和 Redisson 依赖。
<dependencies>
<!-- RocketMQ -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.9.3</version>
</dependency>
<!-- Redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.0</version>
</dependency>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
RocketmqConsumerManager.java
:消费者管理类。
package com.kabai;
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 org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Component
public class RocketmqConsumerManager {
private DefaultMQPushConsumer consumer;
private final RedissonClient redissonClient;
public RocketmqConsumerManager(RedissonClient redissonClient,
@Value("${rocketmq.namesrvAddr}") String namesrvAddr,
@Value("${rocketmq.consumer.groupName}") String consumerGroup) throws MQClientException {
this.redissonClient = redissonClient;
// 创建一个消费者实例
consumer = new DefaultMQPushConsumer(consumerGroup);
consumer.setNamesrvAddr(namesrvAddr);
consumer.start(); // 启动消费者实例
}
public void consumeMsg(String topic) throws MQClientException {
if (consumer == null) {
throw new IllegalStateException("Consumer is not started. Please start the consumer first.");
}
consumer.subscribe(topic, "*");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
for (MessageExt msg : msgs) {
String msgId = msg.getMsgId();
RLock lock = redissonClient.getLock("lock:" + msgId);
try {
// 尝试获取锁
if (lock.tryLock(5000, TimeUnit.MILLISECONDS)) {
try {
// 消费消息
System.out.println("Received message: " + new String(msg.getBody()));
} finally {
// 释放锁
lock.unlock();
}
} else {
System.out.println("Failed to acquire lock for message: " + msgId);
}
} catch (Exception e) {
System.err.println("Error processing message: " + msgId + ", " + e);
}
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
}
public void shutdownConsumer() {
if (consumer != null) {
consumer.shutdown(); // 关闭消费者实例
}
}
}
- 消费者的 Spring Boot 应用程序主类。
package com.kabai;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RocketmqConsumerApplication implements CommandLineRunner {
@Autowired
private RocketmqConsumerManager rocketmqConsumerManager;
public static void main(String[] args) {
SpringApplication.run(RocketmqConsumerApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
// 启动消费者并消费消息
rocketmqConsumerManager.consumeMsg("TopicTest");
// 模拟运行一段时间后关闭消费者
Thread.sleep(5000);
rocketmqConsumerManager.shutdownConsumer();
}
}
application.properties
:配置文件。
rocketmq.namesrvAddr=127.0.0.1:9876
rocketmq.consumer.groupName=ReliableConsumerGroup
RedissonConfig.java
:Redisson 配置类,用于在生产者和消费者应用中共享。
package com.kabai;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Redisson
Config {
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
return Redisson.create(config);
}
}
关键点
- 生产者和消费者分离:生产者和消费者逻辑分别放在不同的 Spring Boot 应用程序中。
- 依赖管理:在各自的
pom.xml
中添加 RocketMQ 和 Redisson 的依赖。 - 管理类:使用 Spring 的
@Component
注解管理生产者和消费者的逻辑。 - Redisson 配置:在两个应用程序中共享 Redisson 配置类。
- Spring Boot 主类:在
CommandLineRunner
中实现生产者和消费者的启动逻辑。
通过这种方式,您可以在两个独立的 Spring Boot 应用程序中管理 RocketMQ 的生产者和消费者逻辑,并使用 Redisson 实现分布式锁。