摘要:本文通过完整案例演示Spring Boot与RabbitMQ的整合过程,深入讲解异步通信原理与消息可靠性保证机制。包含交换机类型选择、消息持久化配置、手动ACK确认等核心功能实现。
组件 | 作用 | 类比现实场景 |
---|---|---|
Producer | 消息生产者 | 快递发货方 |
Consumer | 消息消费者 | 快递收货方 |
Exchange | 消息路由规则制定者 | 快递分拣中心 |
Queue | 消息存储队列 | 快递暂存仓库 |
Binding | 交换机和队列的绑定规则 | 快递配送路线 |
# 使用Docker启动RabbitMQ(带管理界面)
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=123456 docker.1ms.run/rabbitmq:3-management
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
dependency>
# application.yml
spring:
rabbitmq:
host: localhost
port: 5672
username: admin
password: 123456
virtual-host: /
# 开启发送方确认机制
publisher-confirm-type: correlated
# 开启发送方回退模式
publisher-returns: true
@Configuration
public class RabbitMQConfig {
// 订单队列
@Bean
public Queue orderQueue() {
return new Queue("order.queue", true); // 持久化队列
}
// 直连交换机
@Bean
public DirectExchange orderExchange() {
return new DirectExchange("order.exchange");
}
// 绑定关系
@Bean
public Binding orderBinding() {
return BindingBuilder.bind(orderQueue())
.to(orderExchange()).with("order.routingKey");
}
}
通过RabbitMQ管理界面创建(可选):
http://localhost:15672
。admin
和密码 123456
登录。order.queue
,并勾选 Durable。order.exchange
,选择类型为 Direct,并勾选 Durable。order.queue
,输入路由键 order.routingKey
。@Service
@RequiredArgsConstructor
public class OrderProducer {
private final RabbitTemplate rabbitTemplate;
public void sendOrder(Order order) {
// 消息唯一ID
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplate.convertAndSend(
"order.exchange",
"order.routingKey",
order,
message -> {
// 消息持久化
message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
return message;
},
correlationData
);
}
}
@Component
@Slf4j
public class OrderConsumer {
@RabbitListener(queues = "order.queue")
public void processOrder(Order order, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
try {
// 业务处理逻辑
log.info("收到订单消息: {}", order);
// 手动ACK确认
channel.basicAck(tag, false);
} catch (Exception e) {
// 消息重试或进入死信队列
channel.basicNack(tag, false, true);
}
}
}
@PostMapping("/sendMs")
public void sendMs(@RequestBody Ms ms){
Order o = new Order();
o.setId(1L);
o.setName("test 1234");
// 发送消息
orderProducer.sendOrder(o);
}
测试截图:
@Slf4j
@Component
public class RabbitConfirmCallback implements RabbitTemplate.ConfirmCallback,
RabbitTemplate.ReturnsCallback {
@Autowired
public RabbitConfirmCallback(RabbitTemplate rabbitTemplate) {
rabbitTemplate.setConfirmCallback(this);
rabbitTemplate.setReturnsCallback(this);
}
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (ack) {
log.info("消息到达交换机,ID: {}", correlationData.getId());
} else {
log.error("消息投递失败,ID: {},原因: {}", correlationData.getId(), cause);
}
}
@Override
public void returnedMessage(ReturnedMessage returned) {
log.warn("消息无法路由,即将返回给生产者: {}", returned.getMessage());
}
}
spring:
rabbitmq:
listener:
simple:
acknowledge-mode: manual # 开启手动确认
retry:
enabled: true # 开启重试
max-attempts: 3 # 最大重试次数
@Bean
public Queue deadLetterQueue() {
return QueueBuilder.durable("dead.letter.queue").build();
}
@Bean
public DirectExchange deadLetterExchange() {
return new DirectExchange("dead.letter.exchange");
}
@Bean
public Binding deadLetterBinding() {
return BindingBuilder.bind(deadLetterQueue())
.to(deadLetterExchange()).with("dead.letter.routingKey");
}
@Bean
public Queue orderQueueWithDLX() {
return QueueBuilder.durable("order.queue")
.deadLetterExchange("dead.letter.exchange")
.deadLetterRoutingKey("dead.letter.routingKey")
.build();
}
// 队列级别TTL
@Bean
public Queue ttlQueue() {
return QueueBuilder.durable("ttl.queue")
.ttl(60000) // 单位毫秒
.build();
}
// 消息级别TTL
MessageProperties props = MessagePropertiesBuilder.newInstance()
.setExpiration("30000")
.build();
rabbitTemplate.convertAndSend(exchange, routingKey, message, props);
spring:
rabbitmq:
cache:
channel:
size: 50 # 通道缓存数量
checkout-timeout: 1000 # 获取通道超时时间
spring:
rabbitmq:
listener:
simple:
prefetch: 10 # 每个消费者最大未确认数
message.getMessageProperties().setHeader("compression", "gzip");
问题1:消息重复消费
问题2:队列消息堆积
问题3:连接自动断开
spring:
rabbitmq:
requested-heartbeat: 60 # 心跳间隔(秒)
参考资料:
RabbitMQ官方文档
希望本教程对您有帮助,请点赞❤️收藏⭐关注支持!欢迎在评论区留言交流技术细节!