问题背景:
1.Springboot+Rabbitmq项目启动后不能自动创建交换机和队列
2.消费者和生产者是在2个不同微服务中
3.先启动生产者的模块, 启动成功, 但是交换机和队列没有创建, 然后启动消费者一直启动失败
4.生产者的微服务配置了交换机队列和绑定key的声明, 消费者直接监听了队列,没有填写配置信息
开发阶段为啥没发现这个问题:
1. 本地idea链接开发的Rabbitmq服务器, 然后运行启动和debug启动, Rabbitmq可以创建交换机和队列;
2. 然后在开发服务器,启动服务, Rabbitmq可以不可以创建交换机和队列;
最终问题解决:
把交换机队列和绑定key的配置声明写到消费者微服务一份, 然后消费者启动的时候就会自动创建;
排查问题思路:
1. 确认RabbitMQ连接配置
-
检查配置文件:确保生产环境和开发服务器的
application.properties
或application.yml
中RabbitMQ配置正确。properties
spring.rabbitmq.host=your-rabbitmq-host spring.rabbitmq.port=5672 spring.rabbitmq.username=your-username spring.rabbitmq.password=your-password spring.rabbitmq.virtual-host=your-vhost
-
验证网络连接:确保开发服务器可以访问RabbitMQ服务器的IP和端口,使用
telnet
或nc
测试连通性。
2. 检查用户权限
-
登录RabbitMQ管理界面,确认使用的用户对目标虚拟主机具有以下权限:
-
Configure:允许创建交换机和队列。
-
Write:允许发布消息。
-
Read:允许订阅队列。
-
-
使用命令行调整权限:
bash
复制
rabbitmqctl set_permissions -p /vhost 用户名 ".*" ".*" ".*"
3. 显式声明Exchange和Queue的Bean
-
在生产者模块声明Exchange:
java
@Configuration public class ProducerRabbitConfig {@Beanpublic DirectExchange myExchange() {return new DirectExchange("myExchange", true, false); // durable=true, autoDelete=false} }
-
在消费者模块声明Queue和Binding:
java
@Configuration public class ConsumerRabbitConfig {@Beanpublic DirectExchange myExchange() {return new DirectExchange("myExchange", true, false); // 参数必须与生产者一致}@Beanpublic Queue myQueue() {return new Queue("myQueue", true, false, false); // durable=true}@Beanpublic Binding binding(Queue myQueue, DirectExchange myExchange) {return BindingBuilder.bind(myQueue).to(myExchange).with("myRoutingKey");} }
4. 确保配置参数一致性
-
检查所有服务中Exchange和Queue的以下参数是否一致:
-
名称:完全一致。
-
类型(如Direct、Topic)。
-
Durable(持久化):建议设为
true
。 -
AutoDelete:根据需求设置,确保各服务一致。
-
5. 检查Spring Boot自动配置
-
确认依赖:两个服务均引入
spring-boot-starter-amqp
。xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency>
运行 HTML
-
排除配置干扰:确保没有使用
@EnableAutoConfiguration(exclude = {...})
排除RabbitMQ自动配置。
6. 分析应用启动日志
-
查找声明日志:启动时搜索关键字
Declaring exchange
或Declaring queue
,确认Bean被加载。 -
捕获异常信息:检查是否有权限错误、参数冲突或连接失败日志。
7. 手动测试RabbitMQ操作
-
在服务器上执行声明命令:
bash
复制
# 使用rabbitmqadmin工具声明Exchange rabbitmqadmin declare exchange --vhost=your-vhost name=myExchange type=direct durable=true # 声明Queue rabbitmqadmin declare queue --vhost=your-vhost name=myQueue durable=true
-
验证是否成功:通过管理界面或命令行查看是否存在对应Exchange和Queue。
8. 验证配置类加载
-
添加测试Bean:在配置类中加入测试输出,确认配置类被扫描。
java
@Bean public ApplicationRunner init() {return args -> System.out.println("RabbitMQ配置类已加载!"); }
9. 处理可能的启动顺序问题
-
消费者服务增加重试机制:在消费者配置中,添加监听容器重试,避免因RabbitMQ组件未就绪导致启动失败。
properties
spring.rabbitmq.listener.simple.retry.enabled=true spring.rabbitmq.listener.simple.retry.max-attempts=5 spring.rabbitmq.listener.simple.retry.initial-interval=3000
10. 最终验证
-
启动顺序测试:
-
仅启动生产者服务:检查日志中是否成功声明Exchange,管理界面确认存在。
-
启动消费者服务:确认Queue和Binding被创建,并与Exchange正确绑定。
-
-
消息发送测试:通过生产者发送消息,验证消费者是否能正常接收。
反思:
我直接把交换机和队列和绑定配置直接放到生产者和消费者微服务各一份解决了问题;为啥我们项目之前没出现过这个问题呢, 排查发现, 之前我们用队列都是在同一个微服务中, 所以没有这个问题;
欢迎各位技术大佬交流意见