Spring Boot集成RabbitMQ的各种队列使用案例

一、项目依赖配置

1. Maven依赖

<!-- RabbitMQ -->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-amqp</artifactId>

</dependency>

<!-- 引入Jackson 用于消息数据绑定-->

<dependency>

<groupId>com.fasterxml.jackson.core</groupId>

<artifactId>jackson-databind</artifactId>

</dependency>

2. application.yml配置

spring:

rabbitmq:

host: localhost

port: 5672

username: guest

password: guest

virtual-host: /

开启消息确认机制

publisher-confirm-type: correlated

publisher-returns: true

listener:

simple:

acknowledge-mode: manual # 手动ACK

prefetch: 1

二、RabbitMQ配置类

import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;

import java.util.Map;

@Slf4j

@Configuration

public class RabbitMQConfig {

@Autowired

private RabbitTemplate rabbitTemplate;

// 普通队列

public static final String NORMAL_QUEUE = "normal.queue";

public static final String NORMAL_EXCHANGE = "normal.exchange";

public static final String NORMAL_ROUTING_KEY = "normal.key";

// 延迟队列(使用死信队列实现)

public static final String DELAY_QUEUE = "delay.queue";

public static final String DELAY_EXCHANGE = "delay.exchange";

public static final String DELAY_ROUTING_KEY = "delay.key";

// 死信队列配置

public static final String DLX_EXCHANGE = "dlx.exchange";

public static final String DLX_QUEUE = "dlx.queue";

public static final String DLX_ROUTING_KEY = "dlx.key";

// 持久队列(实心队列)

public static final String DURABLE_QUEUE = "durable.queue";

public static final String DURABLE_EXCHANGE = "durable.exchange";

public static final String DURABLE_ROUTING_KEY = "durable.key";

/**

* JSON消息转换器

*/

@Bean

public Jackson2JsonMessageConverter jsonMessageConverter() {

return new Jackson2JsonMessageConverter();

}

/**

* 配置容器工厂

*/

@Bean

public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(

ConnectionFactory connectionFactory) {

SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();

factory.setConnectionFactory(connectionFactory);

factory.setMessageConverter(jsonMessageConverter());

factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);

return factory;

}

// ==================== 普通队列配置 ====================

@Bean

public Queue normalQueue() {

return new Queue(NORMAL_QUEUE, true); // true表示持久化

}

@Bean

public DirectExchange normalExchange() {

return new DirectExchange(NORMAL_EXCHANGE, true, false);

}

@Bean

public Binding normalBinding() {

return BindingBuilder.bind(normalQueue())

.to(normalExchange())

.with(NORMAL_ROUTING_KEY);

}

// ==================== 延迟队列配置(使用死信队列)====================

/**

* 死信交换机

*/

@Bean

public DirectExchange dlxExchange() {

return new DirectExchange(DLX_EXCHANGE, true, false);

}

/**

* 死信队列(实际消费的队列)

*/

@Bean

public Queue dlxQueue() {

return new Queue(DLX_QUEUE, true);

}

@Bean

public Binding dlxBinding() {

return BindingBuilder.bind(dlxQueue())

.to(dlxExchange())

.with(DLX_ROUTING_KEY);

}

/**

* 延迟队列(消息过期后进入死信队列)

*/

@Bean

public Queue delayQueue() {

Map<String, Object> args = new HashMap<>();

// 设置死信交换机

args.put("x-dead-letter-exchange", DLX_EXCHANGE);

// 设置死信路由键

args.put("x-dead-letter-routing-key", DLX_ROUTING_KEY);

// 设置队列消息过期时间(毫秒)

args.put("x-message-ttl", 10000); // 10秒

return QueueBuilder.durable(DELAY_QUEUE).withArguments(args).build();

}

@Bean

public DirectExchange delayExchange() {

return new DirectExchange(DELAY_EXCHANGE, true, false);

}

@Bean

public Binding delayBinding() {

return BindingBuilder.bind(delayQueue())

.to(delayExchange())

.with(DELAY_ROUTING_KEY);

}

// ==================== 持久队列(实心队列)配置 ====================

@Bean

public Queue durableQueue() {

return QueueBuilder.durable(DURABLE_QUEUE)

.withArgument("x-max-length", 10000) // 队列最大长度

.withArgument("x-max-length-bytes", 104857600) // 队列最大字节数 100MB

.withArgument("x-queue-mode", "lazy") // 惰性队列,消息直接写入磁盘

.build();

}

@Bean

public DirectExchange durableExchange() {

return new DirectExchange(DURABLE_EXCHANGE, true, false);

}

@Bean

public Binding durableBinding() {

return BindingBuilder.bind(durableQueue())

.to(durableExchange())

.with(DURABLE_ROUTING_KEY);

}

// 在 RabbitMQConfig 类中添加

@PostConstruct

public void initRabbitTemplate() {

rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {

if (ack) {

log.info("消息发送成功,ID: {}", correlationData != null ? correlationData.getId() : "unknown");

} else {

log.error("消息发送失败,ID: {},原因: {}",

correlationData != null ? correlationData.getId() : "unknown", cause);

}

});

rabbitTemplate.setReturnsCallback(returned -> {

log.error("消息发送到队列失败: {}", returned.getMessage());

});

}

}

三、消息生产者

import com.fasterxml.jackson.databind.ObjectMapper;

import org.springframework.amqp.core.Message;

import org.springframework.amqp.core.MessageBuilder;

import org.springframework.amqp.core.MessageDeliveryMode;

import org.springframework.amqp.rabbit.core.RabbitTemplate;

import org.springframework.amqp.rabbit.connection.CorrelationData;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.io.IOException;

import java.util.UUID;

import java.util.concurrent.CompletableFuture;

@Component

public class RabbitMQProducer {

private static final Logger logger = LoggerFactory.getLogger(RabbitMQProducer.class);

@Autowired

private RabbitTemplate rabbitTemplate;

@Autowired

private ObjectMapper objectMapper;

/**

* 发送普通消息

*/

public void sendNormalMessage(Object message) {

CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());

rabbitTemplate.convertAndSend(

RabbitMQConfig.NORMAL_EXCHANGE,

RabbitMQConfig.NORMAL_ROUTING_KEY,

message,

msg -> {

// 设置消息持久化

msg.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);

return msg;

},

correlationData

);

// 由于 CorrelationData.getFuture() 返回 ListenableFuture,不能直接使用 addCallback

// 建议通过配置 RabbitTemplate 的 confirm callback 来处理确认

logger.info("消息已发送,ID: {}", correlationData.getId());

}

/**

* 发送延迟消息(固定延迟时间)

*/

public void sendDelayMessage(Object message, int delaySeconds) {

CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());

rabbitTemplate.convertAndSend(

RabbitMQConfig.DELAY_EXCHANGE,

RabbitMQConfig.DELAY_ROUTING_KEY,

message,

msg -> {

msg.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);

// 设置消息过期时间(毫秒)

msg.getMessageProperties().setExpiration(String.valueOf(delaySeconds * 1000));

return msg;

},

correlationData

);

logger.info("发送延迟消息,将在 {} 秒后消费,ID: {}", delaySeconds, correlationData.getId());

}

/**

* 发送延迟消息(每条消息独立设置延迟时间)

*/

public void sendDelayMessageWithTTL(Object message, int ttl) {

try {

// 创建消息

byte[] body = objectMapper.writeValueAsBytes(message);

Message msg = MessageBuilder

.withBody(body)

.setDeliveryMode(MessageDeliveryMode.PERSISTENT)

.setExpiration(String.valueOf(ttl))

.build();

rabbitTemplate.send(

RabbitMQConfig.DELAY_EXCHANGE,

RabbitMQConfig.DELAY_ROUTING_KEY,

msg

);

logger.info("发送TTL消息,TTL: {} 毫秒", ttl);

} catch (IOException e) {

logger.error("序列化消息失败: {}", e.getMessage(), e);

}

}

/**

* 发送到持久队列(实心队列)

*/

public void sendToDurableQueue(Object message) {

try {

// 创建持久化消息

byte[] body = objectMapper.writeValueAsBytes(message);

Message msg = MessageBuilder

.withBody(body)

.setDeliveryMode(MessageDeliveryMode.PERSISTENT)

.setContentType("application/json")

.build();

rabbitTemplate.send(

RabbitMQConfig.DURABLE_EXCHANGE,

RabbitMQConfig.DURABLE_ROUTING_KEY,

msg

);

logger.info("消息已发送到持久队列");

} catch (IOException e) {

logger.error("序列化消息失败: {}", e.getMessage(), e);

} catch (Exception e) {

logger.error("发送消息到持久队列失败: {}", e.getMessage(), e);

}

}

}

四、消息消费者

import com.fasterxml.jackson.databind.ObjectMapper;

import com.rabbitmq.client.Channel;

import org.springframework.amqp.core.Message;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;

import org.springframework.amqp.rabbit.annotation.RabbitListener;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

import java.io.IOException;

import java.util.Map;

@Component

public class RabbitMQConsumer {

@Autowired

private ObjectMapper objectMapper;

// ==================== 普通队列消费者 ====================

@RabbitListener(queues = RabbitMQConfig.NORMAL_QUEUE)

public void processNormalMessage(Message message, Channel channel) throws IOException {

try {

String msg = new String(message.getBody(), "UTF-8");

System.out.println("收到普通队列消息: " + msg);

// 业务处理逻辑

// ...

// 手动确认消息(成功)

channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

} catch (Exception e) {

System.err.println("处理消息失败: " + e.getMessage());

// 处理失败,可以选择:

// 1. 重试(重新入队)

// channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);

// 2. 拒绝消息,进入死信队列

channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);

}

}

// ==================== 延迟队列消费者(实际消费死信队列)====================

@RabbitListener(queues = RabbitMQConfig.DLX_QUEUE)

public void processDelayMessage(Message message, Channel channel) throws IOException {

try {

String msg = new String(message.getBody(), "UTF-8");

System.out.println("收到延迟队列消息: " + msg);

System.out.println("消息延迟结束,开始处理...");

// 业务处理逻辑

// ...

channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

} catch (Exception e) {

System.err.println("处理延迟消息失败: " + e.getMessage());

channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);

}

}

// ==================== 持久队列消费者 ====================

@RabbitListener(queues = RabbitMQConfig.DURABLE_QUEUE)

public void processDurableMessage(Message message, Channel channel) throws IOException {

try {

Map<String, Object> data = objectMapper.readValue(

message.getBody(),

Map.class

);

System.out.println("收到持久队列消息: " + data);

// 处理大量数据或需要持久化的任务

// ...

channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

} catch (Exception e) {

System.err.println("处理持久队列消息失败: " + e.getMessage());

channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true); // 重试

}

}

}

五、业务应用案例

1. 订单服务案例

import org.springframework.stereotype.Service;

import java.util.Date;

@Service

public class OrderService {

@Autowired

private RabbitMQProducer rabbitMQProducer;

/**

* 创建订单

*/

public void createOrder(OrderDTO orderDTO) {

// 1. 保存订单到数据库

// orderRepository.save(order);

// 2. 发送订单创建消息到普通队列

rabbitMQProducer.sendNormalMessage(orderDTO);

// 3. 发送订单超时延迟消息(30分钟未支付自动取消)

Map<String, Object> timeoutMsg = Map.of(

"orderId", orderDTO.getId(),

"type", "ORDER_TIMEOUT",

"createTime", new Date()

);

rabbitMQProducer.sendDelayMessage(timeoutMsg, 30 * 60); // 30分钟

// 4. 发送订单确认持久消息

Map<String, Object> confirmMsg = Map.of(

"orderId", orderDTO.getId(),

"userId", orderDTO.getUserId(),

"amount", orderDTO.getAmount(),

"status", "PENDING"

);

rabbitMQProducer.sendToDurableQueue(confirmMsg);

}

}

@Data

public class OrderDTO {

private String id;

private String userId;

private BigDecimal amount;

private Date createTime;

}

2. 通知服务案例

@Service

public class NotificationService {

@Autowired

private RabbitMQProducer rabbitMQProducer;

/**

* 发送短信通知(带重试机制)

*/

public void sendSMS(String phone, String content) {

Map<String, Object> smsMsg = Map.of(

"phone", phone,

"content", content,

"retryCount", 0,

"maxRetry", 3,

"timestamp", System.currentTimeMillis()

);

rabbitMQProducer.sendToDurableQueue(smsMsg);

}

/**

* 发送定时提醒

*/

public void scheduleReminder(String userId, String message, Date remindTime) {

Map<String, Object> reminder = Map.of(

"userId", userId,

"message", message,

"scheduledTime", remindTime.getTime()

);

// 计算延迟时间

long delay = remindTime.getTime() - System.currentTimeMillis();

if (delay > 0) {

rabbitMQProducer.sendDelayMessage(reminder, (int)(delay / 1000));

}

}

}

相关推荐
qq_124987075318 小时前
基于springboot归家租房小程序的设计与实现(源码+论文+部署+安装)
java·大数据·spring boot·后端·小程序·毕业设计·计算机毕业设计
内存不泄露18 小时前
基于Spring Boot和Vue的宠物医院管理系统设计与实现
vue.js·spring boot·信息可视化
廋到被风吹走18 小时前
【Spring】Spring Boot Actuator 深度解析:健康检查、指标暴露与端点安全
spring boot·安全·spring
利刃大大18 小时前
【RabbitMQ】安装详解 && 什么是MQ && RabbitMQ介绍
分布式·中间件·消息队列·rabbitmq·mq
怦怦蓝18 小时前
详解 IntelliJ IDEA 中编写邮件发送功能(从环境搭建到实战落地)
java·spring boot·intellij-idea
幽络源小助理19 小时前
springboot基于Java的教学辅助平台源码 – SpringBoot+Vue项目免费下载 | 幽络源
java·vue.js·spring boot
杜子不疼.20 小时前
计算机视觉热门模型手册:Spring Boot 3.2 自动装配新机制:@AutoConfiguration 使用指南
人工智能·spring boot·计算机视觉
indexsunny1 天前
互联网大厂Java求职面试实战:Spring Boot微服务与Redis缓存场景解析
java·spring boot·redis·缓存·微服务·消息队列·电商
28岁青春痘老男孩1 天前
JDK8+SpringBoot2.x 升级 JDK 17 + Spring Boot 3.x
java·spring boot