SpringBoot整合RabbitMQ实现数据同步
·
下面我将详细介绍如何使用SpringBoot整合RabbitMQ实现数据同步,包括配置步骤和代码实现。
一、项目配置
1. 添加依赖
首先在pom.xml中添加RabbitMQ和SpringBoot相关依赖:
<dependencies>
<!-- Spring Boot Starter for RabbitMQ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- Spring Boot Starter Web (可选,如果需要REST接口) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok (可选,简化代码) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
2. 配置文件
在application.yml或application.properties中添加RabbitMQ配置:
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
# 生产者配置
publisher-confirm-type: correlated # 发布确认
publisher-returns: true # 发布返回
# 消费者配置
listener:
simple:
acknowledge-mode: manual # 手动确认
prefetch: 10 # 每次从broker拉取的消息数量
二、代码实现
1. 创建RabbitMQ配置类
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableRabbit
public class RabbitMQConfig {
// 定义数据同步的交换机和队列名称
public static final String DATA_SYNC_EXCHANGE = "data.sync.exchange";
public static final String DATA_SYNC_QUEUE = "data.sync.queue";
public static final String DATA_SYNC_ROUTING_KEY = "data.sync.routing.key";
// 创建直连交换机
@Bean
public DirectExchange dataSyncExchange() {
return new DirectExchange(DATA_SYNC_EXCHANGE, true, false);
}
// 创建队列
@Bean
public Queue dataSyncQueue() {
return QueueBuilder.durable(DATA_SYNC_QUEUE)
.withArgument("x-queue-mode", "lazy") // 惰性队列,消息直接持久化到磁盘
.build();
}
// 绑定队列到交换机
@Bean
public Binding dataSyncBinding() {
return BindingBuilder.bind(dataSyncQueue())
.to(dataSyncExchange())
.with(DATA_SYNC_ROUTING_KEY);
}
// 配置JSON消息转换器
@Bean
public Jackson2JsonMessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
// 配置RabbitTemplate
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(jsonMessageConverter());
// 消息发送到Exchange确认回调
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
System.out.println("消息发送到Exchange成功: " + correlationData);
} else {
System.out.println("消息发送到Exchange失败: " + cause);
}
});
// 消息从Exchange路由到Queue失败回调
rabbitTemplate.setReturnsCallback(returned -> {
System.out.println("消息从Exchange路由到Queue失败: " + returned.getMessage());
});
return rabbitTemplate;
}
}
2. 创建消息生产者
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
@Slf4j
@Service
public class DataSyncProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private ObjectMapper objectMapper;
/**
* 发送数据同步消息
* @param data 要同步的数据
*/
public void sendDataSyncMessage(Object data) {
try {
// 将数据转换为JSON字符串
String jsonData = objectMapper.writeValueAsString(data);
// 构建消息
Message message = MessageBuilder.withBody(jsonData.getBytes(StandardCharsets.UTF_8))
.setContentType(MessageProperties.CONTENT_TYPE_JSON)
.setMessageId(UUID.randomUUID().toString())
.build();
// 发送消息
rabbitTemplate.convertAndSend(
RabbitMQConfig.DATA_SYNC_EXCHANGE,
RabbitMQConfig.DATA_SYNC_ROUTING_KEY,
message,
correlationData -> {
correlationData.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
return correlationData;
}
);
log.info("数据同步消息发送成功: {}", jsonData);
} catch (JsonProcessingException e) {
log.error("数据序列化失败: {}", e.getMessage(), e);
}
}
}
3. 创建消息消费者
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Slf4j
@Service
public class DataSyncConsumer {
@Autowired
private ObjectMapper objectMapper;
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 接收并处理数据同步消息
*/
@RabbitListener(queues = RabbitMQConfig.DATA_SYNC_QUEUE)
public void handleDataSyncMessage(@Payload Message message) throws IOException {
try {
// 获取消息内容
String jsonData = new String(message.getBody(), StandardCharsets.UTF_8);
// 这里根据实际业务需求解析数据
// 示例:假设同步的是用户数据
User user = objectMapper.readValue(jsonData, new TypeReference<User>() {});
log.info("接收到数据同步消息: {}", user);
// 处理数据同步逻辑
processDataSync(user);
// 手动确认消息已处理
rabbitTemplate.execute(channel -> {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
channel.basicAck(deliveryTag, false);
return null;
});
} catch (Exception e) {
log.error("处理数据同步消息失败: {}", e.getMessage(), e);
// 处理失败,可以选择重试或放入死信队列
rabbitTemplate.execute(channel -> {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
channel.basicNack(deliveryTag, false, false);
return null;
});
}
}
private void processDataSync(User user) {
// 这里实现具体的数据同步逻辑
// 例如:将数据保存到数据库、更新缓存等
log.info("正在同步用户数据: {}", user);
// 模拟业务处理
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
log.info("用户数据同步完成: {}", user);
}
}
4. 创建实体类(示例)
import lombok.Data;
@Data
public class User {
private Long id;
private String username;
private String email;
private String phone;
}
5. 创建测试Controller(可选)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DataSyncController {
@Autowired
private DataSyncProducer dataSyncProducer;
@PostMapping("/sync/user")
public String syncUserData(@RequestBody User user) {
dataSyncProducer.sendDataSyncMessage(user);
return "用户数据同步请求已发送";
}
}
三、高级配置(可选)
1. 死信队列配置
在RabbitMQConfig中添加死信队列配置:
// 死信交换机
@Bean
public DirectExchange dataSyncDlxExchange() {
return new DirectExchange("data.sync.dlx.exchange", true, false);
}
// 死信队列
@Bean
public Queue dataSyncDlxQueue() {
return QueueBuilder.durable("data.sync.dlx.queue").build();
}
// 绑定死信队列
@Bean
public Binding dataSyncDlxBinding() {
return BindingBuilder.bind(dataSyncDlxQueue())
.to(dataSyncDlxExchange())
.with("data.sync.dlx.routing.key");
}
// 修改主队列配置,添加死信设置
@Bean
public Queue dataSyncQueue() {
return QueueBuilder.durable(DATA_SYNC_QUEUE)
.withArgument("x-queue-mode", "lazy")
.withArgument("x-dead-letter-exchange", "data.sync.dlx.exchange")
.withArgument("x-dead-letter-routing-key", "data.sync.dlx.routing.key")
.withArgument("x-message-ttl", 10000) // 消息存活时间10秒
.withArgument("x-max-length", 1000) // 队列最大长度
.build();
}
2. 消费者并发配置
在application.yml中增加消费者并发配置:
spring:
rabbitmq:
listener:
simple:
concurrency: 5 # 最小消费者数量
max-concurrency: 10 # 最大消费者数量
四、测试流程
-
启动RabbitMQ服务
-
启动SpringBoot应用
-
使用Postman或curl发送POST请求到
/sync/user接口 -
观察控制台日志,确认消息发送和消费过程
五、关键点说明
-
消息确认机制:
-
生产者通过
publisher-confirm-type和publisher-returns确保消息正确发送到Exchange和Queue -
消费者通过手动确认(
acknowledge-mode: manual)确保消息正确处理
-
-
消息持久化:
-
队列设置为持久化(
durable) -
消息设置为持久化(
setDeliveryMode(MessageDeliveryMode.PERSISTENT))
-
-
异常处理:
-
消费者处理失败时可以选择重试或进入死信队列
-
-
性能考虑:
-
使用惰性队列(
x-queue-mode: lazy)减少内存使用 -
合理设置预取数量(
prefetch)和并发消费者数量
-
通过以上配置和代码,可以实现一个健壮的基于SpringBoot和RabbitMQ的数据同步系统。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)