一、项目依赖配置
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));
}
}
}