You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 16:13:23