Camel loopDoWhile循环中setHeader设置currentpage_start_time_x仅生效一次的问题排查求助
嘿,这个问题其实是Apache Camel中表达式惰性求值+缓存机制和运行时即时执行的差异导致的,我来帮你拆解清楚:
核心原因
1. simple()表达式的缓存特性
你用simple(Long.valueOf(System.currentTimeMillis()).toString())设置Header时,Camel的Simple表达式在路由初始化阶段就会编译并计算这个表达式的值,而且默认会缓存这个结果。也就是说,System.currentTimeMillis()只在路由启动时执行了一次,之后每次循环都会复用这个缓存的固定值,所以看起来currentpage_start_time_x只被设置了一次。
Camel的Simple表达式对这类直接调用Java静态方法的场景,会默认判定结果是"静态不变"的,因此做了缓存优化——这是很多Camel新手容易踩的坑!
2. Process中的即时执行
而你在process()里调用exg.getIn().setHeader("currentpage_start_time", System.currentTimeMillis())时,这段代码是在每次循环的运行时阶段执行的:每走一遍循环流程,都会触发这个Process节点,重新调用System.currentTimeMillis(),所以这个Header的值会随着循环次数动态更新。
排查与解决思路
先验证缓存问题
你可以临时修改Simple表达式为Camel内置的动态日期函数,快速验证是不是缓存的问题:
.setHeader("currentpage_start_time_x", simple("${date:now:yyyyMMddHHmmssSSS}"))
这个表达式是动态的,每次循环都会重新计算当前时间,你会发现currentpage_start_time_x现在也会跟着循环更新了——这就能实锤是Simple的缓存机制在搞鬼。
替换写法实现动态设置
如果要保留在setHeader里设置的方式,推荐两种靠谱方案:
- 方案1:用Groovy表达式(需引入groovy依赖)
Groovy表达式每次都会在运行时执行,不会缓存结果:.setHeader("currentpage_start_time_x", groovy("System.currentTimeMillis().toString()")) - 方案2:统一用Process设置
直接沿用你设置currentpage_start_time的方式,最直观也不会有缓存问题:.process(exg -> { exg.getIn().setHeader("currentpage_start_time_x", String.valueOf(System.currentTimeMillis())); })
额外排查参考
可以去查看Camel官方文档中关于Simple表达式的缓存说明,确认哪些场景会触发缓存——一般来说,内置的动态函数(比如date:now、bean调用)不会被缓存,而直接调用静态Java方法的表达式会被缓存。
修改后的完整示例代码:
from("direct:api-query") .loopDoWhile(simple("${in.header.continue}")) .log(LoggingLevel.DEBUG," send to next page to \n -> {{project.query.url}}?limit={{project.query.limit}}&page=${in.header.currentPage}") .to("metrics:timer:simple.timer?action=start") // 用Groovy实现动态设置 .setHeader("currentpage_start_time_x", groovy("System.currentTimeMillis().toString()")) .process( exg->{ LOG.info("currentpage_start_time_x->{} , currentpage_start_time->{}", exg.getIn().getHeader("currentpage_start_time_x"), exg.getIn().getHeader("currentpage_start_time")); exg.getIn().setHeader("currentpage_start_time", System.currentTimeMillis()); } )
内容的提问来源于stack exchange,提问作者stewchicken

