Camel路由异常处理:消息需发至ReplyTo与错误队列的问题
嘿,我来帮你搞定这个问题!你的核心问题有两个:一是错误消息进入GENERAL.ERRORS后很快被移到DLQ,二是没有通过JMSReplyTo回复客户端。咱们一步步解决:
问题根源分析
你当前的onException块没有标记异常为已处理,Camel默认会让原消息继续留在ActiveMQ的重试队列中,不断重试触发异常,直到达到重试次数上限后,原消息被移到DLQ。而你看到GENERAL.ERRORS里的消息消失,其实是每次重试都会往这个队列发一条新消息,最终原消息的重试流程走完后,你误以为是同一条消息被移走了。另外,你也没添加回复JMSReplyTo的逻辑。
修正后的路由配置
我帮你调整了代码,解决这两个问题:
// 全局异常处理 onException(Exception.class) .handled(true) // 标记异常已处理,阻止原消息被ActiveMQ重试 .log(LoggingLevel.ERROR, "errors", "Processing failed:\nMessage: ${body}\nHeaders: ${headers}\nException Stacktrace: ${exception.stacktrace}") // 格式化错误响应内容(同时用于发送错误队列和回复客户端) .transform().simple("Error occurred while processing message:\nOriginal Body:\n${body}\nError Message: ${exception.message}") // 发送格式化后的错误消息到GENERAL.ERRORS队列 .to("activemq:queue:GENERAL.ERRORS") // 仅当JMSReplyTo头存在时,回复客户端 .choice() .when(header("JMSReplyTo").isNotNull()) .toD("activemq:${header.JMSReplyTo}") // 动态路由到JMSReplyTo指定的目的地 .end() .end(); from("activemq:queue:changeProfitCenter.input") .choice() .when(header("JMSType").isEqualTo("xml")) .to("direct:xmlChangeProfitCenter") .when(header("JMSType").isEqualTo("json")) .to("direct:jsonChangeProfitCenter") .otherwise() .transform(simple("Incorrect message type JMSType = '${header.JMSType}'")) // 手动触发异常,让全局异常处理统一处理回复逻辑 .throwException(new IllegalArgumentException("Invalid JMSType header")) .end() .end(); from("direct:jsonChangeProfitCenter") .unmarshal().json(JsonLibrary.Jackson, Request.class) .log(LoggingLevel.INFO, "unmarshal json : ${body}") .bean(testService, "changeProfitCenter") .log(LoggingLevel.INFO, "service response : ${body}") .end(); from("direct:xmlChangeProfitCenter") .unmarshal().jaxb("model") .log(LoggingLevel.INFO, "unmarshal xml : ${body}") .bean(testService, "changeProfitCenter") .log(LoggingLevel.INFO, "service response : ${body}") .end();
关键改动说明
handled(true):这是解决DLQ问题的核心。它告诉Camel异常已经被完全处理,会主动向ActiveMQ发送ACK,原消息不会被重试,自然也不会被移到DLQ。- 动态回复
JMSReplyTo:用toD(动态路由)根据JMSReplyTo头的值发送回复,同时加了非空判断,避免空指针异常。 - 补充otherwise分支的异常触发:原来的otherwise分支只是转换了消息体,但没有触发异常,不会走到
onException逻辑。我加了throwException,确保这种情况也能被全局异常处理捕获,统一回复客户端。
这样调整后,当出现ParseException或其他异常时:
- 异常会被捕获、格式化并记录日志
- 错误消息会存入
GENERAL.ERRORS队列且不会被自动移走 - 客户端会通过
JMSReplyTo收到错误回复 - 原消息会被正常ACK,不会进入重试流程
内容的提问来源于stack exchange,提问作者Алексей Ефанов
相关产品推荐
相关产品推荐

