一、RabbitMQ核心概念回顾
在开始应用开发之前,先回顾RabbitMQ的核心组件:
-
Producer:消息生产者
-
Consumer:消息消费者
-
Exchange:消息路由器
-
Queue:消息存储队列
-
Connection:TCP连接
-
Channel:虚拟通道
-
Binding:Exchange与Queue的绑定关系
这些组件共同构成了RabbitMQ的消息流转模型:Producer → Exchange → Binding → Queue → Consumer
二、RabbitMQ Java客户端基础编程模型
2.1 Maven依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.21.0</version>
</dependency>
2.2 基础编程七步法
Step 1:创建连接与Channel
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setPort(5672);
factory.setUsername("admin");
factory.setPassword("admin");
factory.setVirtualHost("/");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
注意:一个Connection可创建多个Channel,支持多线程并发。
Step 2:声明Exchange
channel.exchangeDeclare(
"my_exchange", // exchange名称
BuiltInExchangeType.DIRECT, // 类型:DIRECT、FANOUT、TOPIC、HEADERS
true, // durable:是否持久化
false, // autoDelete:是否自动删除
null // arguments:额外参数
);
Step 3:声明Queue
// Classic经典队列(默认)
channel.queueDeclare(
"my_queue", // queue名称
true, // durable:是否持久化
false, // exclusive:是否独占
false, // autoDelete:是否自动删除
null // arguments:额外参数
);
// Quorum队列(推荐)
Map<String, Object> params = new HashMap<>();
params.put("x-queue-type", "quorum");
channel.queueDeclare("quorum_queue", true, false, false, params);
// Stream队列
Map<String, Object> streamParams = new HashMap<>();
streamParams.put("x-queue-type", "stream");
streamParams.put("x-max-length-bytes", 20_000_000_000L); // 20GB
streamParams.put("x-stream-max-segment-size-bytes", 100_000_000); // 100MB
channel.queueDeclare("stream_queue", true, false, false, streamParams);
Step 4:声明Binding
channel.queueBind(
"my_queue", // queue名称
"my_exchange", // exchange名称
"routing.key" // routingKey
);
Step 5:发送消息
// 基础发送
String message = "Hello RabbitMQ!";
channel.basicPublish(
"my_exchange", // exchange名称
"routing.key", // routingKey
null, // props:消息属性
message.getBytes("UTF-8")
);
// 带属性发送
AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder();
builder.deliveryMode(2); // 持久化消息
builder.priority(5); // 优先级
builder.contentType("text/plain");
builder.headers(new HashMap<String, Object>(){{ put("traceId", "12345"); }});
AMQP.BasicProperties props = builder.build();
channel.basicPublish("my_exchange", "routing.key", props, message.getBytes("UTF-8"));
Step 6:消费消息
Push模式(推荐)
// 自动确认
channel.basicConsume("my_queue", true, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
AMQP.BasicProperties properties, byte[] body) {
String message = new String(body, "UTF-8");
System.out.println("收到消息: " + message);
}
});
// 手动确认
channel.basicConsume("my_queue", false, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
AMQP.BasicProperties properties, byte[] body) {
String message = new String(body, "UTF-8");
System.out.println("收到消息: " + message);
// 手动确认
channel.basicAck(envelope.getDeliveryTag(), false);
}
});
Pull模式
GetResponse response = channel.basicGet("my_queue", false);
if (response != null) {
String message = new String(response.getBody(), "UTF-8");
System.out.println("收到消息: " + message);
// 手动确认
channel.basicAck(response.getEnvelope().getDeliveryTag(), false);
}
Step 7:释放资源
channel.close();
connection.close();
三、RabbitMQ七大消息场景详解
3.1 Hello World(简单队列)
场景:一个生产者,一个消费者,直接发送到队列
// Producer
channel.queueDeclare("hello_queue", false, false, false, null);
channel.basicPublish("", "hello_queue", null, "Hello World".getBytes());
// Consumer
channel.queueDeclare("hello_queue", false, false, false, null);
channel.basicConsume("hello_queue", true, consumer);
3.2 Work Queues(工作队列)
场景:一个生产者,多个消费者,竞争消费
// Producer - 发送持久化消息
channel.queueDeclare("task_queue", true, false, false, null);
String message = "Task #" + i;
channel.basicPublish("", "task_queue",
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes());
// Consumer - 设置QoS
channel.queueDeclare("task_queue", true, false, false, null);
channel.basicQos(1); // 每次只处理一条消息
channel.basicConsume("task_queue", false, consumer);
关键点:
-
消息持久化(Queue + Message)
-
手动确认(避免消息丢失)
-
公平分发(basicQos)
3.3 Publish/Subscribe(发布订阅)
场景:一个生产者,多个消费者,每个消费者都收到所有消息
// Producer - 使用Fanout Exchange
channel.exchangeDeclare("logs", BuiltInExchangeType.FANOUT);
channel.basicPublish("logs", "", null, message.getBytes());
// Consumer - 绑定临时队列
channel.exchangeDeclare("logs", BuiltInExchangeType.FANOUT);
String queueName = channel.queueDeclare().getQueue(); // 临时队列
channel.queueBind(queueName, "logs", "");
channel.basicConsume(queueName, true, consumer);
3.4 Routing(路由)
场景:根据routingKey精确匹配分发消息
// Producer - 发送带routingKey的消息
channel.exchangeDeclare("direct_logs", BuiltInExchangeType.DIRECT);
channel.basicPublish("direct_logs", "error", null, message.getBytes());
// Consumer - 按routingKey绑定
String queueName = channel.queueDeclare().getQueue();
channel.queueBind(queueName, "direct_logs", "error");
channel.queueBind(queueName, "direct_logs", "warning");
3.5 Topics(主题)
场景:根据routingKey模式匹配分发消息
// Producer - 发送带routingKey的消息
channel.exchangeDeclare("topic_logs", BuiltInExchangeType.TOPIC);
channel.basicPublish("topic_logs", "order.created.us", null, message.getBytes());
// Consumer - 使用通配符绑定
// * - 一个单词
// # - 零个或多个单词
channel.queueBind(queueName, "topic_logs", "order.*.us"); // 匹配:order.created.us
channel.queueBind(queueName, "topic_logs", "order.#"); // 匹配所有order开头的
3.6 Publisher Confirms(发布者确认)
场景:确保消息成功发送到Broker
// 开启确认模式
channel.confirmSelect();
// 1. 单条确认(同步,性能低)
channel.basicPublish("", "queue", null, message.getBytes());
channel.waitForConfirmsOrDie(5_000);
// 2. 批量确认
int batchSize = 100;
int outstandingMessageCount = 0;
for (int i = 0; i < 1000; i++) {
channel.basicPublish("", "queue", null, message.getBytes());
outstandingMessageCount++;
if (outstandingMessageCount == batchSize) {
channel.waitForConfirmsOrDie(5_000);
outstandingMessageCount = 0;
}
}
// 3. 异步确认(推荐)
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleAck(long deliveryTag, boolean multiple) {
// 消息确认成功
}
@Override
public void handleNack(long deliveryTag, boolean multiple) {
// 消息确认失败,需要重发
}
});
// 获取消息序列号
int sequenceNumber = channel.getNextPublishSeqNo();
3.7 Headers(头部路由)
场景:根据消息头(headers)匹配分发消息
// Producer - 发送带headers的消息
Map<String, Object> headers = new HashMap<>();
headers.put("loglevel", "error");
headers.put("region", "us");
AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder();
builder.headers(headers);
channel.exchangeDeclare("headers_exchange", BuiltInExchangeType.HEADERS);
channel.basicPublish("headers_exchange", "", builder.build(), message.getBytes());
// Consumer - 按headers匹配
Map<String, Object> bindingHeaders = new HashMap<>();
bindingHeaders.put("x-match", "any"); // any或all
bindingHeaders.put("loglevel", "error");
bindingHeaders.put("region", "us");
channel.queueBind(queueName, "headers_exchange", "", bindingHeaders);
四、SpringBoot集成RabbitMQ
4.1 Maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
4.2 配置文件
# application.yml
spring:
rabbitmq:
host: localhost
port: 5672
username: admin
password: admin
virtual-host: /
# 连接池配置
connection-timeout: 10000
# 生产者确认
publisher-confirm-type: correlated
publisher-returns: true
# 消费者配置
listener:
simple:
acknowledge-mode: manual # 手动确认
prefetch: 1 # 每次处理一条
concurrency: 3 # 并发消费者数
max-concurrency: 10 # 最大并发数
4.3 声明Exchange、Queue、Binding
@Configuration
public class RabbitMQConfig {
// 声明Direct Exchange
@Bean
public DirectExchange directExchange() {
return new DirectExchange("direct.exchange", true, false);
}
// 声明Queue
@Bean
public Queue orderQueue() {
Map<String, Object> args = new HashMap<>();
args.put("x-queue-type", "quorum");
return new Queue("order.queue", true, false, false, args);
}
// 声明Binding
@Bean
public Binding orderBinding() {
return BindingBuilder.bind(orderQueue())
.to(directExchange())
.with("order.created");
}
}
4.4 发送消息
@Service
public class OrderService {
@Autowired
private RabbitTemplate rabbitTemplate;
public void createOrder(Order order) {
// 发送简单消息
rabbitTemplate.convertAndSend("direct.exchange",
"order.created",
order);
// 发送带属性的消息
Message message = MessageBuilder
.withBody(order.toString().getBytes())
.setHeader("traceId", UUID.randomUUID().toString())
.setDeliveryMode(MessageDeliveryMode.PERSISTENT)
.build();
rabbitTemplate.send("direct.exchange", "order.created", message);
// 异步确认回调
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
System.out.println("消息发送成功: " + correlationData);
} else {
System.out.println("消息发送失败: " + cause);
}
});
}
}
4.5 消费消息
@Component
public class OrderConsumer {
// 简单消费
@RabbitListener(queues = "order.queue")
public void processOrder(Order order) {
System.out.println("收到订单: " + order);
}
// 手动确认
@RabbitListener(queues = "order.queue")
public void processOrderWithAck(Order order,
Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
try {
System.out.println("处理订单: " + order);
// 业务处理...
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
// 处理失败,拒绝消息(可配置重试)
channel.basicNack(deliveryTag, false, true);
}
}
// 批量消费
@RabbitListener(queues = "order.queue",
containerFactory = "batchFactory")
public void processOrders(List<Message> messages, Channel channel) {
for (Message message : messages) {
System.out.println("批量处理: " + new String(message.getBody()));
}
}
// 配置批量消费容器工厂
@Bean
public SimpleRabbitListenerContainerFactory batchFactory(
ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setBatchListener(true); // 开启批量消费
factory.setBatchSize(10); // 每批10条
factory.setConsumerBatchEnabled(true);
return factory;
}
}
五、高级特性与最佳实践
5.1 消息可靠性保障
// 1. 持久化队列
channel.queueDeclare("queue", true, false, false, null);
// 2. 持久化消息
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
.deliveryMode(2) // 2表示持久化
.build();
// 3. 生产者确认
channel.confirmSelect();
channel.addConfirmListener(confirmListener);
// 4. 消费者手动确认
channel.basicConsume("queue", false, consumer);
5.2 消息重试机制
@Configuration
public class RetryConfig {
@Bean
public MessageRecoverer messageRecoverer() {
// 重试耗尽后进入死信队列
return new RepublishMessageRecoverer(rabbitTemplate,
"error.exchange",
"error.routing");
}
@Bean
public SimpleRabbitListenerContainerFactory retryFactory(
ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
// 配置重试策略
RetryTemplate retryTemplate = new RetryTemplate();
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
backOffPolicy.setInitialInterval(1000);
backOffPolicy.setMultiplier(2.0);
backOffPolicy.setMaxInterval(10000);
retryTemplate.setBackOffPolicy(backOffPolicy);
factory.setRetryTemplate(retryTemplate);
return factory;
}
}
5.3 死信队列
@Bean
public Queue orderQueue() {
Map<String, Object> args = new HashMap<>();
// 设置死信交换机
args.put("x-dead-letter-exchange", "dlx.exchange");
// 设置死信RoutingKey
args.put("x-dead-letter-routing-key", "order.dl");
// 消息TTL(毫秒)
args.put("x-message-ttl", 60000);
// 队列最大长度
args.put("x-max-length", 10000);
return new Queue("order.queue", true, false, false, args);
}
@Bean
public DirectExchange dlxExchange() {
return new DirectExchange("dlx.exchange", true, false);
}
@Bean
public Queue dlQueue() {
return new Queue("dl.queue", true);
}
@Bean
public Binding dlBinding() {
return BindingBuilder.bind(dlQueue())
.to(dlxExchange())
.with("order.dl");
}
六、性能调优建议
-
连接管理:使用连接池,避免频繁创建连接
-
Channel复用:一个线程使用一个Channel
-
批量操作:批量发送、批量确认
-
QoS设置:合理设置prefetchCount
-
队列类型选择:
-
高吞吐:Classic队列(镜像模式)
-
高可靠:Quorum队列
-
流式处理:Stream队列
-
-
持久化权衡:非关键业务可使用非持久化提升性能
七、常见问题与解决方案
问题1:消息丢失怎么办?
解决方案:
-
开启生产者确认
-
开启持久化(队列+消息)
-
消费者手动确认
-
开启Return机制
问题2:消息重复消费怎么办?
解决方案:
-
保证消费幂等性
-
使用数据库唯一约束
-
使用Redis分布式锁
问题3:消息积压怎么办?
解决方案:
-
增加消费者数量
-
调整prefetchCount
-
使用惰性队列(Lazy Queue)
-
设置队列最大长度
八、总结
RabbitMQ作为一款成熟的消息中间件,在企业级应用开发中扮演着重要角色。通过本文的学习,你应该掌握:
-
✅ RabbitMQ的Java客户端编程模型
-
✅ 七大消息场景的应用与选择
-
✅ SpringBoot集成RabbitMQ的最佳实践
-
✅ 高级特性与生产环境调优
实战建议:
-
从简单的Hello World开始,逐步体验各种Exchange类型
-
在生产环境中开启Publisher Confirms和消息持久化
-
合理设置消费者QoS,避免消息积压
-
建立监控告警机制,关注队列长度、消费者数量等指标