当前位置: 首页 > 知识库问答 >
问题:

如果处理了内部路由中的异常,则不执行具有聚合策略的Splitter后的代码(Apache Camel)

梁丘俊材
2023-03-14

我面对过我无法理解的行为。执行“聚合策略”拆分时,会发生此问题,并且在其中一次迭代期间发生异常。在另一个路由(每次迭代调用的直接终结点)中,拆分器内部发生异常。似乎路由执行在拆分器之后停止。

下面是示例代码。

这是一个路由,每个客户端生成一个报告,并收集文件名称以进行内部统计信息。


    @Component
    @RequiredArgsConstructor
    @FieldDefaults(level = PRIVATE, makeFinal = true)
    public class ReportRouteBuilder extends RouteBuilder {
    
      ClientRepository clientRepository;
    
      @Override
      public void configure() throws Exception {
        errorHandler(deadLetterChannel("direct:handleError")); //handles an error, adds error message to internal error collector for statistic and writes log
    
        from("direct:generateReports")
        
            .setProperty("reportTask", body()) //at this point there is in the body an object of type ReportTask, containig all data required for building report
    
            .bean(clientRepository, "getAllClients") // Body is a List<Client>
            
            .split(body())
              .aggregationStrategy(new FileNamesListAggregationStrategy())
              .to("direct:generateReportForClient") // creates report which is saved in the file system. uses the same error handler
            .end()
            
            //when an exception occurs during split then code after splitter is not executed
    
            .log("Finished generating reports. Files created ${body}"); // Body has to be List<String> with file names.
      }
    }

AggregationStrategy非常简单,它只提取文件名。如果没有标头,则返回NULL。


    public class FileNamesListAggregationStrategy extends AbstractListAggregationStrategy<String> {
    
      @Override
      public String getValue(Exchange exchange) {
        Message inMessage = exchange.getIn();
        return inMessage.getHeader(Exchange.FILE_NAME, String.class);
      }
    }

当分割后一切顺利时,在主体列表中有所有文件名。但是当在路由“direct:generateReportForClient”中出现一些异常时(我已经为一个客户端添加了错误模拟),聚合主体只包含少一个文件名——没关系(所有内容都被正确聚合)。

但是,在路由执行停止并且此时主体中的结果(带有文件名的列表)被返回给期望ReportTask作为响应主体的客户端(FluentProducer)之后,就在Split之后。

并尝试将值 - 列表(聚合结果)转换为报告任务,并导致组织.apache.camel.NoType转换可用异常:没有类型转换器可用于从类型转换

为什么路线在拆分后中断?已正确处理所有错误并完成聚合。

另外,我读过关于拆分器的骆驼在行动的书和文档,但我没有找到答案。

PPS项目在Spring Boot 2.3.1和Camel 3.3.0上运行

更新 此路由由 Fluent生产者模板启动

    ReportTask processedReportTask = producer.to("direct:generateReports")
            .withBody(reportTask)
            .request(ReportTask.class);

共有1个答案

段干宾白
2023-03-14

问题是错误处理程序自定义聚合策略中的拆分。

来自骆驼在行动书(5.3.5):

警告 将自定义聚合策略与拆分器一起使用时,请务必了解你负责处理异常。如果不将异常传播回去,拆分器将假定您已经处理了异常,并将忽略它。

在您的代码中,您使用从< code > abstractlistaggationstrategy 扩展的聚合策略。让我们看看< code > abstractlistaggegationstrategy 中的< code>aggregate方法:

@Override
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
    List<V> list;

    if (oldExchange == null) {
        list = getList(newExchange);
    } else {
        list = getList(oldExchange);
    }

    if (newExchange != null) {
        V value = getValue(newExchange);
        if (value != null) {
            list.add(value);
        }
    }

    return oldExchange != null ? oldExchange : newExchange;
}

如果第一次交换由错误处理程序处理,我们将在结果交换(< code>newExchange)中拥有由错误处理程序(< code>Exchange)设置的属性数。EXCEPTION _ catched,Exchange。失败_endpoint,交换。ERRORHANDLER_HANDLED和Exchange。FAILURE_HANDLED)和< code > exchange . errorhandler HANDLED = true 。< code>ExtendedExchange接口中提供了< code > getErrorHandlerHandled()/setErrorHandlerHandled(Boolean errorHandlerHandled)方法。

在这种情况下,您的拆分以errorHandlerHandled=true的交换结束,它会中断路由。

原因在骆驼例外条款手册中有描述

如果handled为true,则将处理抛出的异常,Camel将不会继续在原始路由中路由,而是中断。

为了防止这种行为,您可以将exchange强制转换为ExtendedExchange,并在聚合策略聚合method中设置

  @Override
  public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
    Exchange aggregatedExchange = super.aggregate(oldExchange, newExchange);
    ((ExtendedExchange) aggregatedExchange).setErrorHandlerHandled(false);
    return aggregatedExchange;
  }

棘手的情况是,如果Error Handler处理的交换不是聚合策略中的第一个交换,则不会面临任何问题。因为camel将使用第一个交换(没有errorHandlerHandled=true)作为聚合的基础。

 类似资料:
  • 我想对3条路由使用Apache Camel并行组播,聚合(并等待)其中的2条路由,而让第3条路由自行进行(第3条路由不应阻塞前两条路由)。我还需要在“所有”情况下处理这两个,这意味着如果其中一个失败(例如在处理过程中抛出异常),也应该对其进行聚合。 根据我从Camel文档中了解到的情况,只要不指定StoponException,该行为就应该是“默认的”。但发生的情况是exchange异常永远不会到

  • 我有一个特殊的情况,我需要捕获异常并将一个对象返回给客户端来代替异常。我不能将异常处理逻辑放在更高的级别,即将 Foo 包装在 try 子句中。 最好用一些样本代码来演示。异常处理逻辑模糊了方法的意图,如果我有,许多相似意图的方法,在Foo类中,我发现自己重复了大部分catch逻辑。 在下面的代码中包装常见异常功能的最佳技术是什么?

  • 我有一个关于Mule 3.3.1 CE中Web服务的问题。我有一个Web服务,它公开了三个操作和一个实现这些操作类。这些操作可以返回结果(积极)或异常(AuthExeception,ValidateExeception,等等)。多亏了SOAP Mule组件,当我提出一个Java异常时,框架能够将Java异常编组在一个SOAP故障中,但是如果我想既返回一个SOAP故障给客户机,又用Mule中的异常策

  • 我的骡子流有点像下面这样:- 现在我的问题出现在SOAP请求中,ID和AGE属性是整数,如果我放入任何字符串值,如,它会抛出错误,如org.apache.CXF.interceptor.Fault:Unmarshalling error:不是一个很自然的数字...现在我如何处理这个并发送自定义消息作为响应...我尝试使用Mule中的catch exception block但我无法处理这个CXF

  • 考虑下面的代码片段 在代码片段1中,方法m1()在抛出声明中有SQLExctive,但它实际上抛出了类型为的引用变量。我在这里期待编译器出错,因为

  • 我正在尝试实现同步调用: 我得到以下例外情况: (节点:22140)UnhandledPromiseRejectionWarning:错误:协议错误(Target.CreateTarget):目标已关闭。在Promise(C:\imageServer\node_modules\puppeteer\lib\connection.js:74:56)在new Promise()在connection.s