Apache Camel 2.16.5:聚合后拆分Exchange写入文件系统异常排查
我仔细看了你的代码,发现几个关键问题导致输出目录没有生成文件,下面逐一分析并给出修复方案:
1. 路由添加时机错误,核心路由未启动
你的Main类里犯了一个常见错误:先启动CamelContext,再添加AggregatorRoute和FileWriter路由。在Apache Camel 2.x版本中,上下文启动后新增的路由不会自动激活,这意味着负责监听input目录、聚合文件的路由,以及写文件的路由根本没在运行,自然无法处理后续逻辑。
修复方法:必须在启动CamelContext之前,把所有需要的路由都添加进去。
2. 聚合后的拆分逻辑错误,无法获取文件内容
你用GroupedExchangeAggregationStrategy聚合3个文件后,Exchange的Body是一个List<Exchange>(每个元素对应一个输入文件的Exchange实例)。直接调用split(body())会把每个Exchange当作拆分元素,后续${body}会输出Exchange对象的字符串形式(比如org.apache.camel.impl.DefaultExchange@xxxx),而不是你需要的文件内容,这也会导致写文件逻辑异常。
修复方法:拆分时需要提取每个Exchange中的实际文件内容,用setBody(simple("${body.in.body}"))来获取每个聚合项的Body。
3. 可选优化:文件读取的锁机制
StringRoute写入文件时,file:input组件可能会在文件还没完全写入(或处于锁定状态)时尝试读取,导致读取失败。可以给file组件加上readLock=changed参数,确保文件写完且内容稳定后再读取。
修正后的完整代码
StringRoute(保持原有逻辑即可)
import org.apache.camel.builder.RouteBuilder; public class StringRoute extends RouteBuilder { public void configure() throws Exception { from("direct:readStrings") .split(body()) .to("file:input?fileExist=Append&fileName=${body}.txt"); } }
AggregatorRoute(修复拆分逻辑)
import org.apache.camel.builder.RouteBuilder; import org.apache.camel.processor.aggregate.GroupedExchangeAggregationStrategy; public class AggregatorRoute extends RouteBuilder { @Override public void configure() throws Exception { from("file:input?readLock=changed") .aggregate(new GroupedExchangeAggregationStrategy()) .constant(true) .completionSize(3) // 拆分聚合后的Exchange列表,提取每个Exchange的Body内容 .split(body()) .setBody(simple("${body.in.body}")) .to("direct:writeFiles"); } }
FileWriter(简化后保留核心逻辑)
import org.apache.camel.builder.RouteBuilder; import org.apache.camel.Processor; import org.apache.camel.Exchange; public class FileWriter extends RouteBuilder { @Override public void configure() throws Exception { from("direct:writeFiles") .process(new Processor() { @Override public void process(Exchange exchange) throws Exception { System.out.println("In FileWriter: " + exchange.getIn().getBody()); } }) .to("file:output?fileName=${body}.txt"); } }
Main类(修复路由添加顺序)
import org.apache.camel.CamelContext; import org.apache.camel.ProducerTemplate; import org.apache.camel.impl.DefaultCamelContext; import java.util.ArrayList; import java.util.List; public class Main { public static void main(String[] args) { CamelContext camelContext = new DefaultCamelContext(); try { // 先添加所有路由,再启动上下文 camelContext.addRoutes(new StringRoute()); camelContext.addRoutes(new AggregatorRoute()); camelContext.addRoutes(new FileWriter()); camelContext.start(); ProducerTemplate producerTemplate = camelContext.createProducerTemplate(); List<String> list = new ArrayList<String>(); String a = "abc"; String b = "cdb"; String c = "efg"; list.add(a); list.add(b); list.add(c); producerTemplate.sendBody("direct:readStrings", list); // 延长等待时间,确保文件处理全流程完成 Thread.sleep(15000); camelContext.stop(); } catch (Exception e) { e.printStackTrace(); } } }
验证步骤
- 确保项目根目录下存在
input和output文件夹(Camel会自动创建,但手动创建更稳妥) - 运行Main类,控制台会输出
In FileWriter: abc、In FileWriter: cdb、In FileWriter: efg的日志 - 打开
output目录,就能看到生成的三个txt文件了
内容的提问来源于stack exchange,提问作者anonymous

