我面对过我无法理解的行为。执行“聚合策略”拆分时,会发生此问题,并且在其中一次迭代期间发生异常。在另一个路由(每次迭代调用的直接终结点)中,拆分器内部发生异常。似乎路由执行在拆分器之后停止。
下面是示例代码。
这是一个路由,每个客户端生成一个报告,并收集文件名称以进行内部统计信息。
@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);
问题是错误处理程序自定义聚合策略中的拆分。
来自骆驼在行动书(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异常永远不会到
我有一个关于Mule 3.3.1 CE中Web服务的问题。我有一个Web服务,它公开了三个操作和一个实现这些操作类。这些操作可以返回结果(积极)或异常(AuthExeception,ValidateExeception,等等)。多亏了SOAP Mule组件,当我提出一个Java异常时,框架能够将Java异常编组在一个SOAP故障中,但是如果我想既返回一个SOAP故障给客户机,又用Mule中的异常策
我有一个特殊的情况,我需要捕获异常并将一个对象返回给客户端来代替异常。我不能将异常处理逻辑放在更高的级别,即将 Foo 包装在 try 子句中。 最好用一些样本代码来演示。异常处理逻辑模糊了方法的意图,如果我有,许多相似意图的方法,在Foo类中,我发现自己重复了大部分catch逻辑。 在下面的代码中包装常见异常功能的最佳技术是什么?
我的骡子流有点像下面这样:- 现在我的问题出现在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