资讯动态

SpringBoot整合RabbitMQ使用AmqpTemplate发送消息实战

发布时间:2026/10/15 5:32:50 来源:尧图企业网站定制
1. 项目概述与核心价值做后端开发的朋友应该都有过这种经历系统里某个模块处理完业务后需要通知另一个模块去执行后续操作。最原始的办法就是同步调用接口但一旦对方服务响应慢、接口抖动或者宕机调用方就得跟着遭殃——超时、重试、线程阻塞整套链路都被拖垮。后来我开始引入MQ来解耦其中RabbitMQ用的最多而在SpringBoot项目里操作RabbitMQ最顺手的方式就是通过Spring官方提供的AmqpTemplate。这个项目标题看着简单就是RabbitMQ整合SpringBoot发送消息使用AmqpTemplate但实际做起来里面涉及的东西远不止引入依赖、写个模板方法调用这么简单。你需要理解消息怎么路由到队列、如何设计交换机与绑定关系、消息怎么确认、怎么防止丢失、怎么处理发送失败等等。这些细节如果没搞清楚开发时觉得挺好一上线就会在各种极端场景下踩坑。这篇文章我就按实际项目里的推进顺序把从环境搭建到AmqpTemplate发送消息的完整过程拆开讲包括每一步为什么这么做、参数怎么选、哪些坑我替你先踩了。有一点需要说明本文所有案例基于我个人的模拟项目X一个消息驱动的订单处理系统公司名、项目名均为虚构代称但代码和配置都是实打实在本地环境跑过的可以直接照着复现。适合谁看呢如果你已经会SpringBoot的基本用法但没怎么接触过RabbitMQ或者用过RabbitMQ但一直是照着别人的代码抄也不知道怎么改这篇文章就是给你准备的。我会尽量把原理和实操串起来讲保证你读完不是只学会一个API而是真正理解这套东西是怎么转起来的。2. 环境准备与基础概念梳理2.1 安装RabbitMQ与服务启动先把环境跑起来。RabbitMQ依赖Erlang所以装的时候要注意版本匹配。我自己用的是RabbitMQ 3.9.x搭配Erlang 24.x这套组合兼容性很稳建议你也用这个版本组合不要盲目上最新版——有时候Erlang版本太新反而会和RabbitMQ的管理插件有兼容问题。安装方式分平台简单说本地开发建议直接用Docker。一条命令搞定还不会污染宿主机环境。如果公司强制要求用物理机或虚拟机安装那就去RabbitMQ官网下载对应的安装包按官方文档一步步来。我用的是Docker方式docker run -d --name rabbitmq \ -p 5672:5672 \ -p 15672:15672 \ -e RABBITMQ_DEFAULT_USERadmin \ -e RABBITMQ_DEFAULT_PASSadmin123 \ rabbitmq:3.9-management注意这里选的是带management后缀的镜像它会自带Web管理界面。5672是AMQP协议通信端口15672是管理控制台端口。起完容器后浏览器访问http://localhost:15672用设置的账号密码登录能看到一个图形化界面里面可以查看交换机、队列、消息速率等运行时状态排查问题非常方便。如果你在Windows上装记得先装Erlang再装RabbitMQ装完打开命令行执行rabbitmq-plugins enable rabbitmq_management启用管理界面。Linux上用apt或yum安装后也一样。2.2 四个核心概念交换机、队列、绑定、路由键在动手写代码之前必须把RabbitMQ里的几个核心概念捋清楚。不然你会遇到一个很费解的现象消息明明发送成功了但消费者就是收不到。问题八成出在交换机、队列和绑定的关系没配对。交换机Exchange消息的入口。生产者把消息发给交换机而不是直接发给队列。交换机根据路由规则决定把消息投递到哪个队列。队列Queue真正存储消息的地方。消费者从队列里取消息消费。绑定Binding把交换机和队列关联起来同时指定一个路由键Routing Key。路由键Routing Key交换机用来匹配队列的暗号。我用生活里的场景给你做个类比交换机就是一个快递分拣中心队列是各个片区的中转站路由键是包裹上的地址标签。快递到了分拣中心分拣员看地址标签把包裹放到对应片区的筐里地址标签和筐的编号对得上包裹才会被正确投递。在RabbitMQ里如果路由键对不上消息就丢了注意这里丢了是严格模式下的行为后面细讲。RabbitMQ常用的交换机类型有四种Direct直连、Topic主题、Fanout扇出、Headers请求头。日常开发中用得最多的是Direct和Topic。Direct就是完全匹配路由键Topic则支持通配符匹配*表示一个词#表示零个或多个词。2.3 SpringBoot与AMQP协议的自动配置机制接下来进入SpringBoot。我们知道SpringBoot有个核心特性叫自动配置RabbitMQ的整合也是靠这个机制完成的。引入spring-boot-starter-amqp后SpringBoot会自动创建一个ConnectionFactory连接工厂、一个RabbitAdmin用于声明交换机、队列、绑定、一个RabbitTemplateAmqpTemplate接口的实现类还会自动读取application.yml里的spring.rabbitmq开头的配置项。这个机制意味着什么意味着你不需要自己去写那些样板代码。我在最早接触这一套的时候还傻乎乎地手动创建连接工厂、手动声明队列后面发现SpringBoot全都帮你做了瞬间感觉自己以前写的代码都是多余的。不过要注意自动配置省事但有个隐藏问题RabbitAdmin默认只声明的对象是你通过Bean显式定义的队列、交换机和绑定。如果你在配置文件里写spring.rabbitmq.addresses连接地址却忘了定义队列那么消息发送时如果路由不到任何队列就会悄悄丢失。后面我会讲怎么防止这种情况。3. 核心配置详解与项目搭建3.1 pom.xml依赖引入创建一个SpringBoot项目我用的是2.7.x版本3.x版本的API大体一样但有些细节变动我会在文中提醒引入AMQP启动器依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-amqp/artifactId /dependency这个starter依赖会自动引入spring-rabbitSpring对RabbitMQ的封装和amqp-clientRabbitMQ的Java客户端。不需要手动引入客户端库。如果你需要做消息的JSON序列化通常还会加一个Jackson依赖SpringBoot Web项目默认自带不用额外加。如果要用 Lombok 简化实体类也一并引入。3.2 application.yml配置说明在application.yml里配置连接参数spring: rabbitmq: host: 127.0.0.1 port: 5672 username: admin password: admin123 virtual-host: / publisher-confirm-type: correlated publisher-returns: true template: mandatory: true listener: simple: acknowledge-mode: manual prefetch: 1这里每一条配置都有讲究我逐个说一下host和portRabbitMQ服务地址和端口默认就是127.0.0.1:5672。virtual-host虚拟主机。RabbitMQ支持多租户隔离不同的虚拟主机之间数据完全隔离。默认是/。企业项目里建议按环境拆开比如开发环境用dev测试环境用test互不干扰。publisher-confirm-type: correlated开启发布确认机制。这个配置是SpringBoot 2.1以后的新写法旧版本用的是publisher-confirms: true。开启后生产者发送消息时RabbitMQ会异步回调确认结果告诉你消息已经被broker接收了。publisher-returns: true开启消息路由失败回调。如果交换机接收到消息后找不到匹配的队列会触发ReturnCallback回调前提是mandatory为true。template.mandatory: truemandatory标志意思是如果消息无法被路由到队列broker要把消息退回给生产者而不是静默丢弃。listener.simple.acknowledge-mode: manual消费者手动确认。适合需要严格消息不丢失的场景。这些配置参数是消息可靠性的基石。如果你只是玩玩不配置这些也不影响消息发送但如果是公司项目生产环境一定得把这些配齐否则消息丢失你都发现不了。3.3 定义交换机、队列和绑定关系接下来是核心代码层面的配置。用一个Configuration类来声明交换机、队列和绑定关系Configuration public class RabbitConfig { public static final String EXCHANGE_ORDER exchange.order; public static final String QUEUE_ORDER_CREATE queue.order.create; public static final String QUEUE_ORDER_PAY queue.order.pay; public static final String ROUTING_ORDER_CREATE routing.order.create; public static final String ROUTING_ORDER_PAY routing.order.pay; // 订单交换机direct类型持久化 Bean public DirectExchange orderExchange() { return new DirectExchange(EXCHANGE_ORDER, true, false); } // 两个业务队列 Bean public Queue orderCreateQueue() { return new Queue(QUEUE_ORDER_CREATE, true); } Bean public Queue orderPayQueue() { return new Queue(QUEUE_ORDER_PAY, true); } // 绑定关系把队列bind到交换机并指定路由键 Bean public Binding bindingOrderCreate() { return BindingBuilder .bind(orderCreateQueue()) .to(orderExchange()) .with(ROUTING_ORDER_CREATE); } Bean public Binding bindingOrderPay() { return BindingBuilder .bind(orderPayQueue()) .to(orderExchange()) .with(ROUTING_ORDER_PAY); } }这里用的是DirectExchange也就是说消息带的路由键必须和绑定关系中的路由键完全一致消息才会被投递到对应队列。比如发送消息时设置routingKey routing.order.create这个消息就会进queue.order.create队列消费者监听这个队列就能收到。关于new DirectExchange(EXCHANGE_ORDER, true, false)这三个参数重点解释一下第一个参数交换机名称。第二个参数durable是否持久化。设置为trueRabbitMQ重启后交换机定义不丢失。第三个参数autoDelete是否自动删除。设置为false表示所有队列都解绑后交换机依然保留。队列的new Queue(QUEUE_ORDER_CREATE, true)就更简单了true表示持久化队列。注意队列持久化只代表队列的定义不丢不代表里面存的消息不丢。消息本身的持久化要靠在发送时设置MessageDeliveryMode.PERSISTENT。不过SpringBoot的RabbitTemplate默认就是持久化消息这块你心里有数就行。4. AmqpTemplate发送消息的核心代码实操4.1 AmqpTemplate与RabbitTemplate的关系很多人一上来就问到底用AmqpTemplate还是RabbitTemplate简单说AmqpTemplate是Spring定义的顶层接口定义了消息发送、接收的基本方法RabbitTemplate是Spring对RabbitMQ的实现类。日常编码里推荐面向接口编程也就是注入类型用AmqpTemplateAutowired private AmqpTemplate amqpTemplate;虽然Spring容器里实际注入的是RabbitTemplate实例但用接口声明好处多多后续如果要替换MQ实现比如换Kafka业务代码的改动面会小很多。这是我在团队里一直强调的编码习惯。4.2 最简单的消息发送convertAndSend核心方法就一个convertAndSend它干了三件事把业务对象转成Message默认用SimpleMessageConverter做序列化、设置交换机、设置路由键然后发送出去。public void sendOrderMessage(Order order) { String exchange RabbitConfig.EXCHANGE_ORDER; String routingKey RabbitConfig.ROUTING_ORDER_CREATE; amqpTemplate.convertAndSend(exchange, routingKey, order); }这里的order对象可以是任何POJO。默认情况下SpringBoot会把POJO用JDK序列化处理发送到RabbitMQ后消息体的内容是一串看不懂的二进制数据。如果消费者端也是Java应用可以正常反序列化但如果你想让消息体是JSON更通用、更方便在管理界面查看、也方便跨语言就需要配置MessageConverter。4.3 JSON消息转换器配置我想很多人在这一步就被坑过消费者收到的消息解析不了或者在管理控制台看到一堆乱码。解决方法是自定义消息转换器把默认的JDK序列化换成Jackson JSON转换。Bean public MessageConverter messageConverter() { return new Jackson2JsonMessageConverter(); }加了这段配置后SpringBoot的RabbitTemplate和SimpleRabbitListenerContainerFactory都会自动使用这个JSON转换器。发送时POJO会被序列化成JSON字符串消费时消息体自动反序列化成目标对象。注意一个细节如果消息体是JSON字符串在队列里可以看到完整的消息内容方便用管理界面Debug。这对排查问题特别重要。我有一次线上环境消费者一直报反序列化错误就是靠管理界面看到消息体的字段和消费者定义的实体类字段不一致才定位到问题的。4.4 发送消息时的参数封装与消息属性设置单纯的convertAndSend够用但很多业务场景需要在发送时设置一些消息属性比如过期时间、优先级、消息ID。这时候要用MessagePostProcessorpublic void sendOrderMessageWithDelay(Order order) { amqpTemplate.convertAndSend( RabbitConfig.EXCHANGE_ORDER, RabbitConfig.ROUTING_ORDER_CREATE, order, message - { MessageProperties props message.getMessageProperties(); props.setExpiration(5000); // 消息5秒后过期 props.setPriority(5); // 设置优先级 props.setMessageId(UUID.randomUUID().toString()); // 消息唯一ID return message; } ); }Lambda表达式中的message是org.springframework.amqp.core.Message对象message.getMessageProperties()拿到属性对象可以设置各种属性。注意setExpiration传的是字符串类型的毫秒数。这里有一个很关键的细节setExpiration设置的是消息过期时间当消息在队列中存活超过这个时间且未被消费就会被RabbitMQ删除进入死信交换机的逻辑这里不展开。如果你做过延迟队列就是用这个属性配合死信交换机实现的。4.5 同步发送与异步发送的选择AmqpTemplate的发送方法本质上是异步的——调用convertAndSend后方法立即返回消息真正写入网络是后台线程做的。但对于大多数业务场景你不需要知道消息什么时候真正到达broker只要发送方法不抛异常就可以认为发送成功了。如果你需要确保broker已接收这种强可靠性有两种方案方案一使用同步回调设置CorrelationData然后等待确认。方案二配置publisher-confirm-type: correlated使用异步回调处理确认结果。我在实际项目中用的是异步回调方式public void sendMessageWithConfirm(Order order) { CorrelationData correlationData new CorrelationData(UUID.randomUUID().toString()); amqpTemplate.convertAndSend( RabbitConfig.EXCHANGE_ORDER, RabbitConfig.ROUTING_ORDER_CREATE, order, correlationData ); }然后注册ConfirmCallbackRabbitTemplate rabbitTemplate (RabbitTemplate) amqpTemplate; // 建议在配置类里初始化 rabbitTemplate.setConfirmCallback((correlationData, ack, cause) - { if (ack) { log.info(消息发送成功correlationData: {}, correlationData.getId()); } else { log.error(消息发送失败原因{}, cause); // 这里可以做补偿操作比如存库重试 } });这里说句实话很多人配置了setConfirmCallback但回调就是不触发或者触发特别慢。排除代码问题后百分之九十是publisher-confirm-type没有配置成correlated。SpringBoot 2.x之后默认是none不开启确认机制你注册了回调也白搭。4.6 ReturnCallback与不可路由消息处理前面提到mandatory: true和publisher-returns: true就是配合ReturnCallback用的。当一个消息发送到交换机后交换机根据路由键找不到任何匹配的队列就会执行退回操作触发ReturnCallback。rabbitTemplate.setReturnsCallback(returned - { log.error(消息路由失败交换机: {}, 路由键: {}, 消息体: {}, returned.getExchange(), returned.getRoutingKey(), returned.getMessage()); });有了这个回调你才能发现消息发出去但没进任何队列的异常情况。正常开发调试时我会故意把路由键写错然后观察控制台是否输出了这条错误日志。4.7 消息发送的完整业务封装把上面的东西组合起来一个可落地的发送组件基本长这样Component public class OrderMessageSender { private static final Logger log LoggerFactory.getLogger(OrderMessageSender.class); private final AmqpTemplate amqpTemplate; public OrderMessageSender(AmqpTemplate amqpTemplate) { this.amqpTemplate amqpTemplate; if (amqpTemplate instanceof RabbitTemplate rabbitTemplate) { // 设置回调也可以在配置类中统一设置 rabbitTemplate.setConfirmCallback(this::handleConfirm); rabbitTemplate.setReturnsCallback(this::handleReturn); } } public void sendOrderCreated(Order order) { log.info(发送订单创建消息orderId: {}, order.getOrderId()); amqpTemplate.convertAndSend( RabbitConfig.EXCHANGE_ORDER, RabbitConfig.ROUTING_ORDER_CREATE, order, message - { message.getMessageProperties().setMessageId(UUID.randomUUID().toString()); return message; }); } private void handleConfirm(CorrelationData data, boolean ack, String cause) { if (ack) { log.info(broker已确认接收消息id: {}, data ! null ? data.getId() : null); } else { log.error(broker确认消息失败id: {}, 原因: {}, data ! null ? data.getId() : null, cause); // 实际项目中可以发到补偿表定时任务重发 } } private void handleReturn(ReturnedMessage returned) { log.error(消息被退回exchange: {}, routingKey: {}, replyText: {}, returned.getExchange(), returned.getRoutingKey(), returned.getReplyText()); // 同样走补偿逻辑 } }这套封装建议直接借鉴到项目里。很多初学者觉得写个发送很简单直接把convertAndSend调用写在Service里出了问题时消息没到达、路由错了根本没人知道。加上回调日志之后消息的完整生命周期都有迹可循。5. 扩展实操消费者配置与手动确认既然标题重点是发送消息但消息发出去总要有人消费。消费端配置其实和发送端紧密相关尤其是确认模式直接影响消息是否会被重复消费。所以这里补充讲一下消费者端的关键配置。5.1 消息监听器与手动确认详解消费者的核心是一个带RabbitListener注解的方法Component public class OrderConsumer { RabbitListener(queues RabbitConfig.QUEUE_ORDER_CREATE) public void handleOrderCreate(Order order, Channel channel, Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws IOException { try { log.info(消费订单创建消息: {}, order); // 执行业务逻辑... channel.basicAck(deliveryTag, false); } catch (Exception e) { log.error(消费失败: , e); // 第三个参数是否重新入队。false表示不重新入队消息进入死信队列或丢弃 channel.basicNack(deliveryTag, false, false); } } }几个核心点queues属性指定监听哪个队列。也可以监听多个队列用数组表示。Channel和DELIVERY_TAG从方法参数中注入用于手动确认。basicAck确认消息处理成功RabbitMQ会删除这条消息。basicNack拒绝消息。第二个参数multiple为false表示只拒绝当前这条第三个参数requeue为false表示不重新入队。手动确认模式的核心价值在于消费者处理消息时如果抛了异常消息不会自动丢失而是给了你重试或者进死信的机会。如果是自动确认模式SpringBoot默认是AUTO一收到消息就立刻确认然后业务逻辑跑挂了消息就丢了你还找不回来。我在项目里全部用手动确认宁可代码多点也要保证消息不丢。5.2 并发消费与Prefetch配置RabbitMQ支持多线程消费同一队列。配置如下spring: rabbitmq: listener: simple: concurrency: 5 max-concurrency: 10 prefetch: 2concurrency初始消费者数量。max-concurrency最大消费者数量。prefetch每个消费者一次性预取的消息数量。prefetch这个参数很多人容易理解错。它表示每个消费者在本地缓冲区中最多缓存多少条消息。如果你的消费者处理速度很快prefetch可以设大一点比如20~50减少网络交互次数如果处理的是耗时操作或者希望消费更均衡则prefetch设小一点比如1~5。我踩过一个很典型的坑有一回把prefetch设成100同时开了10个消费者结果高峰期的某类消息把内存撑爆了消费者逐个处理不过来本地堆积了大量消息最后OOM。后面改成prefetch: 10内存压力降下来了消费吞吐量反而更稳定。5.3 死信队列的配置避坑如果消息处理失败且不重新入队需要有一个兜底方案。直接丢弃不可取生产环境我建议加死信队列。所谓死信队列就是装失败消息的队列。实现方式在业务队列声明时指定x-dead-letter-exchange和x-dead-letter-routing-key。Bean public Queue orderCreateQueue() { MapString, Object args new HashMap(); args.put(x-dead-letter-exchange, RabbitConfig.EXCHANGE_DEAD_LETTER); args.put(x-dead-letter-routing-key, RabbitConfig.ROUTING_DEAD_LETTER_CREATE); return new Queue(QUEUE_ORDER_CREATE, true, false, false, args); }这样当消费者执行basicNack(deliveryTag, false, false)或者消息过期时消息会被自动投递到死信队列。之后你可以专门写一个死信消费者把这些消息捞出来、记录错误原因、人工分析问题。一个小细节死信交换机的类型也要是DirectExchange或者和死信路由键匹配的类型否则消息进了死信交换机但路由不到死信队列照样会丢。6. 可靠性与高级消息处理机制6.1 发送消息可靠性分析聊到消息中间件可靠性永远是绕不开的话题。RabbitMQ的消息可靠性可以从三个层面理解生产者层面消息是否正确到达broker。通过publisher-confirm确认机制保障。交换机层面消息是否被正确路由到队列。通过ReturnCallback和mandatory参数保障。队列层面消息在broker中是否被持久化保存。通过消息持久化DeliveryMode.PERSISTENT和队列持久化保障。我的建议是这三层全部要配置。很多人以为加了事务就万事大吉但RabbitMQ的事务和Spring事务完全是两码事而且事务模式性能很差比confirm模式慢好几倍。生产环境优先用confirm模式性能和安全兼顾。6.2 幂等性设计与消费去重消息发送成功后消费者不一定会恰好只处理一次。什么是恰好一次就是不丢不重。RabbitMQ官方只保证至少一次也就是说消息可能会重复投递。所以消费端必须做幂等处理。最常见的方案是在消费者里根据业务唯一ID比如订单ID查询数据库/Redis如果已经处理过就直接返回不再重复执行业务逻辑。public void handleOrderCreate(Order order) { String key order:processed: order.getOrderId(); Boolean first redisTemplate.opsForValue().setIfAbsent(key, 1, Duration.ofHours(24)); if (Boolean.FALSE.equals(first)) { log.info(重复消息直接返回orderId: {}, order.getOrderId()); return; } // 正常业务处理... }这个设计极其重要。一旦消费者处理完消息但确认消息时网络断开了RabbitMQ会重新投递这条消息。没有幂等保护一条消息就可能导致重复下单、重复扣款。我在支付场景里见过一次事故就是典型的没做幂等补偿重构的代价可不小。6.3 消息幂等与补偿建议事务消息方案如果生产者的消息需要和本地业务强一致比如订单落库后必须发送消息可以考虑事务消息方案。使用Spring的RabbitTransactionManager配合Transactional注解让消息发送和本地数据库事务绑定在同一个事务里事务提交后消息才真正发送。Bean public RabbitTransactionManager rabbitTransactionManager(ConnectionFactory connectionFactory) { return new RabbitTransactionManager(connectionFactory); }配置类的Transactional方法内调用convertAndSend如果后续数据库操作抛异常消息发送也会回滚如果消息发送异常数据库也不会提交。这种方案强一致但性能开销比confirm模式大只适合低频但重要的场景。对于多数互联网应用我认为不用所有消息都上事务。事务消息太慢性能损耗不值得。通常的做法是保证publisher-confirm开启配合发送失败后的本地补偿表记录待发送数据定时任务重扫重发。这套方案是业界最常见的最终一致性解法吞吐量高、实现也不复杂。7. 常见问题与排查技巧实录实际操作中我积累了不少边摸索边爆炸的经验。下面把典型的坑和排查方法整理成表方便你遇到问题时快速定位。问题现象可能原因排查方法消费者收不到消息交换机、队列、绑定关系不一致或路由键不匹配在管理控制台找到Exchange点进去看Bindings确认绑定键和发送的路由键完全一致消息发送成功但路由失败mandatory未开启、ReturnCallback未配置开启publisher-returns: true和template.mandatory: true看回调日志输出消息发送后确认回调不触发publisher-confirm-type未配置或配错检查application.yml务必配置publisher-confirm-type: correlated消费者端报反序列化异常生产者和消费者的消息转换器不一致或实体类缺少无参构造两边都配置Jackson2JsonMessageConverter实体类提供无参构造和setter消息被消费两次消费者已经处理完成但确认时网络异常导致重新投递消费端做幂等处理用业务唯一ID去重管理界面打不开镜像不带management插件或防火墙端口未放行使用rabbitmq:3.9-management镜像检查15672端口发送消息超时连接参数错误、rabbitmq服务未启动、网络不通先ping一下5672端口再检查管理界面是否正常连接消息堆积不下发prefetch设置过大消费端处理不过来调小prefetch或者增加消费者并发数我再分享几个常规文档里不会写的排查技巧第一个窍门一定要善用管理控制台的Queue页面。选中一个队列能看到当前堆积的消息数量、消费者连接情况、消息进出的速率。有一回线上消息积压我在管理界面看到队列里堆积了几十万条消息但消费者连接数为0——查了半天发现消费者的RabbitListener注解所在的方法不在Spring扫描的包路径下。这种问题不看控制台你根本猜不到。第二个窍门要养成给每条消息设置messageId的习惯。配合服务端日志如果涉及这条消息从发出去到消费完成花了多久的性能分析没有消息ID你根本无从下手。第三个窍门出现反序列化问题时先别急着看代码打开管理界面找到对应的队列点Get Message看消息体的原始内容。如果看到一串以rO0开头的东西说明是JDK序列化以{开头的是JSON。这个信息能帮你快速判断消费者配置到底对不对。第四个经验是关于RabbitTemplate是线程安全的可以放心地在多线程环境下使用同一个实例。但注意如果为每个线程都创建新的RabbitTemplate连接资源会被浪费甚至耗尽连接数。Spring容器里注入的那个全局单例直接用就行别自己new。8. 实操总结与个人经验体会最后根据我自己的使用体验说几句掏心窝子的话。RabbitMQ整合SpringBoot发送消息这件事入门门槛其实不高三行代码就能把消息发出去。但真正考验人的在于细节消息可靠性怎么保障、重复消费怎么处理、积压怎么排查、路由不通怎么发现。这些问题如果不在设计阶段考虑清楚上了生产环境就是灾难。我自己在模拟项目X里踩过一个印象很深的坑。当时做的是订单中心的改造我用AmqpTemplate.convertAndSend发送订单创建消息觉得一切正常直到测试环境复现一个偶发问题用户下单后部分订单一直没进入后续处理流程。查了很久发现原因很简单——我在发送时用的路由键和生产环境队列绑定里的路由键大小写不一致一个用了Order.Created一个用了order.created。这个错误在本地环境因为是同一个配置文件所以没暴露但测试环境应用有两个配置来源一个覆盖了另一个问题就炸了。从那次以后我把交换机/队列/路由键的命名全部收敛到配置类的常量里杜绝了魔法字符串。这个做法推荐给所有做MQ开发的同事——把队列名、交换机名、路由键都定义成静态常量所有发送和监听的地方引用同一个常量既统一又可维护还不容易出低级错误。后续这个模拟项目X的MQ模块还可以继续扩展比如接入死信队列做延迟消费、用Topic交换机替换Direct交换机来支持更灵活的路由规则、加消息轨迹追踪中间件做链路排查。每一步都不难但都需要你对底层机制有足够清晰的理解。希望这篇基于AmqpTemplate的RabbitMQ整合实战笔记能帮你少走一些弯路。如果按照上面的步骤做下来消息发送这条路应该会很顺。真的遇到奇怪问题记住一句话先登录管理控制台看队列、看交换机、看消息内容八成问题都能一眼定位。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑