【问题标题】:Original Message within the body of camel Exchange is lost骆驼交换体内的原始消息丢失
【发布时间】:2014-03-12 19:11:14
【问题描述】:

我有一条骆驼路线,如下所示。

 from("jms:queue:start")
     .transacted()
     .bean(new FirstDummyBean(), "setBodyToHello")
     .bean(new SecondDummyBean(), "setBodyToWorld")
     .to("jms:queue:end")

bean 方法,顾名思义,将 body 分别设置为“Hello”和“World”。

我还有一个 onException 子句设置,如下所示:

onException(Exception.class)
    .useOriginalMessage()
    .handled(true)
    .to("jms:queue:deadletter")
    .markRollbackOnlyLast(); 

假设,我在队列“开始”上放置了一条消息,正文为“测试消息”。在 FirstDummyBean 中成功处理后,我在 SecondDummyBean 中抛出了一个 RuntimeException。 我期待看到实际消息或(原始消息内容完整,即“测试消息”)被发送到我的死信队列。

但是死信队列上的消息内容是“Hello”。

为什么会这样?..

我正在使用 apache camel 2.10.0。

还有人可以提供更多关于我如何同时使用errorhandler 和oneexception 子句的信息。 文件说:

如果您使用事务处理 DSL 将路由标记为事务处理,则 Camel 将自动使用 TransactionErrorHandler。它将尝试查找 global/per 路由配置的错误处理程序并在其为 TransactionErrorHandlerBuilder
时使用它 实例。如果不是 Camel 会自动创建一个临时的 TransactionErrorHandler 否决默认错误处理程序。这是约定优于配置。

如何在 JavaDSL 中使用 transactionerrorhandler 的示例会很棒。

【问题讨论】:

    标签: java apache-camel


    【解决方案1】:

    我在非事务示例中看到了这一点,看起来useOriginalMessage() 确实使用了原始交换,但是如果您修改了此引用的任何对象,那么您仍然会得到修改。 useOriginalMessage 似乎没有返回队列获取原始数据。

    显示问题的示例代码

    下面的代码包含一组路由来演示问题。定时路由将包含String "Test message"ArrayList 发送到由第二条路由读取的队列。第二条路由将消息传递给ModifyBody,这会更改列表的内容。接下来,消息发送到TriggerException,并抛出RuntimeException。这是由onException 路由处理的,尽管使用了useOriginalMessage,但它传递了更新的主体。

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    import org.apache.camel.spring.SpringRouteBuilder;
    import org.springframework.stereotype.Component;
    
    @Component
    public class TimedRoute extends SpringRouteBuilder {
    
        private static final String QUEUE = "jms:a.queue";
        private static final String QUEUE2 = "jms:another.queue";
        // The message that will be sent on the route
        private static final ArrayList<String> payLoad = new ArrayList<String>(
                Arrays.asList("test message"));
    
        public static class ModifyBody {
            public List<String> modify(final List<String> list) {
                final List<String> returnList = list;
                returnList.clear();
                returnList.add("Hello");
                return returnList;
            }
        }
    
        public static class TriggerException {
            public List<String> trigger(final List<String> list) {
                throw new RuntimeException("Deliberate");
            }
        }
    
        @Override
        public void configure() throws Exception {
            //@formatter:off
            onException(Exception.class)
                 .useOriginalMessage()
                 .log("Exception: ${body}")
                 .handled(true)
                 .setHeader("exception", constant("exception"))
                 .to(QUEUE2);
    
    
            // Timed route to send the original message
            from("timer://foo?period=60000")
               .setBody().constant(payLoad)
               .to(QUEUE);
    
            // Initial processing route - this modifies the body.
            from(QUEUE)
                .log("queue ${body}")
                .bean(new ModifyBody())
                .log("after firstDummyBean: ${body}")
                .bean(new TriggerException())
                .stop();
    
            // Messages are send here by the exception handler.
            from(QUEUE2)
                .log("queue2: ${body}")
                .stop();
            //@formatter:on
        }
    }
    

    解决方法

    如果您将ModifyBody 替换为下面的代码,则会在异常处理路径中看到原始消息。

    public static class ModifyBody {
        public List<String> modify(final List<String> list) {
            final List<String> returnList = new ArrayList<String>(list);
            returnList.clear();
            returnList.add("Hello");
            return returnList;
        }
    }
    

    通过将正文更改为列表,原始Exchange 可以保持不变。

    做一个通用的解决方案是很尴尬的,因为复制的机制将取决于你在飞行中拥有的对象。您可能会发现您可以扩展 RouteBuilder 类来为自己提供一些自定义 DSL 来复制您的对象。

    【讨论】:

    • 感谢您的回复。我的应用程序中有数百条路线。这是否意味着我必须将深拷贝 bean 添加到所有路由中。然而,OnException 子句具有全局范围。您还可以提供一个关于您在 bean 中究竟做了什么的 sn-p。
    • @LearnToLive 我已经用我所看到的问题的更完整示例以及如何避免它的示例更新了我的答案。这和你看到的问题一样吗?
    猜你喜欢
    • 2017-01-03
    • 2012-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-17
    • 2021-10-30
    • 2013-01-24
    相关资源
    最近更新 更多