您当前的位置: 首页 > 慢生活 > 程序人生 网站首页程序人生
尚硅谷RabbitMQ视频-033-进阶篇-死信-产生原因23
发布时间:2026-11-15 03:10:07编辑:雪饮阅读()
-
接续上篇,这次我们新增model33
D:\rabbitMqLearning\ pom.xml中新增
<modules>
<module>currentLimiting</module>
<module>timeout</module>
<module>model32</module>
<module>model33</module>
</modules>
D:\rabbitMqLearning\model33\ pom.xml中新增:
<!--用测试依赖来实现实现生产者-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>然后D:\rabbitMqLearning\model33\src\test\java\org\example\ RabbitMQTest.java:
package org.example;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.amqp.core.MessagePostProcessor;
@SpringBootTest
public class RabbitMQTest {
public static final String EXCHANGE_NORMAL = "exchange.normal.video";
public static final String ROUTING_KEY_NORMAL = "routing.key.normal.video";
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testSendMultiMessage() {
for (int i = 0; i < 20; i++) {
rabbitTemplate.convertAndSend(
EXCHANGE_NORMAL,
ROUTING_KEY_NORMAL,
"测试死信情况2:消息数量超过队列的最大容量" + i);
}
}
}其余的从上篇中的model32中复制过来即可。先停到上篇中的消费者服务
执行发送20条,从控制台中你会发现
为什么我运行D:\rabbitMqLearning\model33\src\test\java\org\example这个里面的testSendMultiMessage方法就自动触发了D:\rabbitMqLearning\model33\src\main\java\org\example\listener\MyMessageListener.java中的与RabbitListener注解相关的方法?按理说我没有运行D:\rabbitMqLearning\model33\src\main\java\org\example\RabbitMQConsumerMainType.java中的main方法,应该就不会自动触发吧?
## 原因:`@SpringBootTest` 会自动启动完整的 Spring 应用上下文,消费者监听器随之注册
你看到的现象是**正常行为**,并不是 bug。关键在于测试类上的这个注解:
@SpringBootTest
public class RabbitMQTest { ... }### `@SpringBootTest` ≠ 只跑一个 JUnit 方法你以为运行 `testSendMultiMessage()` 只是执行一个测试方法,但实际上 Spring Boot 测试框架在跑这个方法之前,会先做一整套动作:
1. **扫描并加载 `@SpringBootApplication` 主类**(也就是 `RabbitMQConsumerMainType`)。
2. **启动 Spring 容器(ApplicationContext)**,完成 Bean 的创建、依赖注入。
3. **自动装配 `RabbitTemplate`、`ConnectionFactory`、`RabbitListenerContainerFactory`** 等 AMQP 组件。
4. **扫描所有 `@Component`**(包括 `MyMessageListener`),并把带 `@RabbitListener` 的方法注册成消费者监听器,自动连接 RabbitMQ 服务器开始监听队列。
也就是说:**虽然你没有手动调用 `RabbitMQConsumerMainType.main()`,但 `@SpringBootTest` 在底层替你 `SpringApplication.run()` 了一遍**。main 方法本身不是启动容器的唯一入口,注解扫描 + 上下文刷新才是。
2. 为什么 main 方法不是必需的
main() 里做的事情只有一行:
SpringApplication.run(RabbitMQConsumerMainType.class, args);
这行代码的本质就是 "启动 Spring 容器"。而 @SpringBootTest 启动测试上下文时,同样会用这个主类作为配置源,完成等价的容器初始化。两者最终走的是同一套 Spring Boot 启动流程,区别只是触发入口不同。
3. 监听器是怎么被自动激活的
MyMessageListener 上有两个注解配合:
@Component // ① 让它成为 Spring 容器管理的 Bean
@RabbitListener(queues = {...}) // ② 让 Spring AMQP 为这个方法建消费者容器并绑定队列
public void processMessageNormal(...) { ... }
- @Component:容器扫描到后,这个类会被实例化放进上下文。
- @RabbitListener:Spring AMQP 后置处理器检测到该注解后,会创建 SimpleMessageListenerContainer,自动去声明 / 连接队列并异步消费消息。
所以我们要关掉监听器容器自动启动
D:\rabbitMqLearning\model33\src\main\resources\application.yml:
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: 123456
virtual-host: /
listener:
simple:
acknowledge-mode: manual # 把消息确认模式改为手动确认,因为默认都是按成功处理,默认都是ack
auto-startup: false #关掉监听器容器自动启动(防止消费者自动启动)
publisher-confirm-type: correlated #交换机的确认(**开启【异步关联发布确认】,用来知道消息有没有成功送到交换机(Broker),发送消息的时候,你可以给这条消息带上一个唯一标识 `CorrelationData`;当 RabbitMQ 交换机收到消息后,回调会把这个标识还给你,**让你精准匹配:是哪一条消息 ack/nack 了。)
publisher-returns: true #队列的确认(作用:开启【消息回退(Return)】机制,消息已经成功发到交换机(exchange),**但是交换机找不到任何队列可以路由这条消息**(routingKey 不匹配、没有队列绑定),此时把这条消息退回给生产者,让生产者感知这个异常)然后重新发送20条消息然后发送结束后稍微过一会儿就发现进入了死信队列了

以为我们前番正常队列配置的是
| x-max-length: | 10 |
队列最多允许存放 10 条 ready(待消费)消息
还有
| x-message-ttl: | 10000 |
单位:毫秒 → 10000ms = 10 秒
关键字词:RabbitMQ,死信,产生原因,进阶篇
上一篇:尚硅谷RabbitMQ视频-032-进阶篇-死信-产生原因1拒绝
下一篇:返回列表