Apache Camel+Spring Boot中JMS请求响应模式问题排查与方案咨询
问题分析与解决方案
核心问题点
1. 模拟路由的响应目标错误
你的模拟路由最后一步把响应发回了请求队列,而非主路由监听的响应队列:
.toD("jms:queue:{{queues.get-document-properties}}");
这会导致响应消息永远不会到达{{queues.get-document-properties-response}},主路由的ConsumerTemplate自然收不到消息。
2. 主路由中ProducerTemplate的消息发送错误
你直接把整个Exchange对象作为消息体发送:
producer.sendBody(endpoint,exchange);
Camel会将整个Exchange序列化后发送,而非你marshal后的XML内容。模拟路由接收到这种消息后,unmarshal(documentPropertiesRequest)会失败,消息被静默丢弃(未配置错误处理时),因此看不到模拟路由的日志。
3. 手动创建Producer/ConsumerTemplate的资源与事务问题
每次循环都创建新的ProducerTemplate和ConsumerTemplate,既浪费资源,还可能引发事务死锁:如果主路由运行在事务中,手动发送的消息会被挂起,直到事务提交,但主路由又在等待响应,形成循环等待,模拟路由永远收不到消息。
可行解决方案
方案1:修复基础逻辑错误
第一步:修正模拟路由的响应目标
把响应发送到正确的响应队列:
from("jms:queue:{{queues.get-document-properties}}") .routeId("mock") .log("Get properties request") .unmarshal(documentPropertiesRequest) .process(<some process>) .marshal(documentPropertiesResponse) .toD("jms:queue:{{queues.get-document-properties-response}}"); // 修改为响应队列
第二步:修正主路由的消息发送方式
不要直接发送Exchange,发送marshal后的消息体:
// 替换原process内的发送逻辑 ProducerTemplate producer = exchange.getContext().createProducerTemplate(); var endpoint = exchange.getContext().getEndpoint("jms:queue:{{queues.get-document-properties}}"); producer.sendBody(endpoint, exchange.getIn().getBody()); // 发送消息体而非整个Exchange
方案2:使用Camel原生InOut模式(推荐)
手动管理模板容易出错,Camel的inOut模式是同步请求响应的标准实现,能自动处理消息发送与响应接收,还能更好地集成事务。
主路由改造示例:
public void route() { from("jms:queue:your-start-queue") // 补充实际启动队列 .loopDoWhile(<some condition>) .choice() .when(<process>) .marshal(documentPropertiesRequest) // InOut模式自动处理请求发送与响应接收 .to("jms:queue:{{queues.get-document-properties}}?exchangePattern=InOut&replyTo={{queues.get-document-properties-response}}") .unmarshal(documentPropertiesResponse) .process(new HandleDocumentPropertiesProcessor()) .endChoice() .end() .end(); }
模拟路由简化(无需硬编码响应队列)
InOut模式会自动将响应发回请求指定的replyTo地址,模拟路由无需额外配置:
from("jms:queue:{{queues.get-document-properties}}") .routeId("mock") .log("Get properties request") .unmarshal(documentPropertiesRequest) .process(<some process>) .marshal(documentPropertiesResponse); // 无需toD,InOut自动处理回复
事务问题处理
如果之前InOut因事务失败,可通过以下方式调整:
- 给JMS组件配置
transacted=false(无需事务覆盖整个请求响应流程时) - 使用独立事务发送请求,避免死锁:
.to("jms:queue:{{queues.get-document-properties}}?exchangePattern=InOut&replyTo={{queues.get-document-properties-response}}&transacted=true&transactionManager=#yourTransactionManager")
方案3:使用PollEnrich实现同步等待响应
若必须拆分发送与接收逻辑,可使用pollEnrich在循环中等待响应,同时保证消息发送在事务外提交:
public void route() { from("jms:queue:your-start-queue") .loopDoWhile(<some condition>) .choice() .when(<process>) .marshal(documentPropertiesRequest) // 事务外发送请求,避免消息挂起 .to("jms:queue:{{queues.get-document-properties}}?transacted=false") // 轮询响应队列,等待3600秒 .pollEnrich("jms:queue:{{queues.get-document-properties-response}}", 3600000) .choice() .when(body().isNull()) .throwException(new ExchangeTimedOutException(exchange, 3600, "Server didn't respond in time")) .otherwise() .unmarshal(documentPropertiesResponse) .process(new HandleDocumentPropertiesProcessor()) .end() .endChoice() .end() .end(); }
内容的提问来源于stack exchange,提问作者HelloThere
相关产品推荐
相关产品推荐

