Debug时加的观察变量影响了debug

一、问题描述

有这样一个流程:从FTP上下载文件后,会根据文件名读取缓存实现防重,其中缓存读取到的值会写入Camel的exchange,exchange.getIn().setBody(cacheValue);

但是,通过日志观察该Body是一串无规律的字符,类似My8+PFNEMvPjxSRU1BUksxLz48UkMRT48TUFUTlI+QVBHTTA0OC02PC9NQVROUj48TUFLVFg+57qi6Imy5Ki75aSn5Y+36LSt54mp6KJWkVTX0RBVEE+PFNJWkU+MDAwPC9VNQVJLMi8+PFJFTUFSSzMvPjxSRU1BUks0Lz48L1NJWkVTX0RBVEE+PC9NQUlOX1RBQkxFPjwvUk9PTUFJTl9UQUJTSVpFPjxXRUlHSFQvPjxMRU5HVEgvPjxXSURUSC8+PEhFSUdIVC8+PElOQ0FTRU1FTlQvPjxFQU5VUKLPVD4D488Uk9PVC9NQUtUW

二、排查路径

1)测试缓存值非null情况

  • 若缓存值非null,则body显示正常

  • 若缓存不存在,Body显示为不规律字符串

2)查看运行日志

  • 发现缓存节点执行结束时,*exchange.getIn.setBody(cacheValue)*的cacheValue变量确实是null。

  • 但是缓存节点之后的日志节点打印的日志中,Body却是不规律字符串

3)远程断点Debug

  • 断点设置在get-cache节点结束位置
    • 验证了cacheValue确实是null
    • 增加自定义变量,类似ElUtils.evaluate(“${body}”, exchange, Object,class),观察到Body为字符串(此时产生了困惑,明明写入的是null,但是获取的body却非空
    • 根据断点时添加的观察变量,发现exchange.getIn()返回的是org.apache.camel.component.file.GenericFileMessage
  • 查看源码org.apache.camel.component.file.GenericFileMessage#setBody
    • 源码里没有对null做特殊处理
1
2
3
4
5
6
7
8
9
public abstract class MessageSupport implements Message, CamelContextAware, DataTypeAware {   
public void setBody(Object body) {
this.body = body;
// set data type if in use
if (body != null && camelContext != null && camelContext.isUseDataType()) {
this.dataType = new DataType(body.getClass());
}
}
}
  • 断点设置在setBody方法里
    • 观察变量this.body值,发现this.body,确实设为null
    • 增加自定义变量,通过*ElUtils.evaluate(“${body}”, exchange, Object,class)*获取body值,发现body设为null后,然后又变为字符串
  • 怀疑是el表达式子,最终调用的getBody方法重置了Body。
  • 查看org.apache.camel.component.file.GenericFileMessage#getBody()
    • 发现GenericFileMessage对null做了特殊处理,为空时会根据file重建body。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public abstract class MessageSupport implements Message, CamelContextAware, DataTypeAware {
@Override
public Object getBody() {
if (body == null) {
body = createBody();
}
return body;
}
}

public class GenericFileMessage<T> extends DefaultMessage {
@Override
protected Object createBody() {
return file != null ? file.getBody() : super.createBody();
}
}

三、总结

此处问题的原因是,流程中FTP构造的Exchange中的message类型为GenericFileMessage,当该类型的message的body属性为空时,调用getBody方法会根据文件内容重置body属性。所以,我们看到哪些混乱的字符串实际上是FTP节点下载的文件内容的一种序列化表现。

总之,在Debug时你定义的观察变量有可能在未知处默默修改系统的运行变量,导致Debug时无法复现Run时的问题。如果有些变量因你观察而变化时,你就要评估下你的自定义变量是否隐式调用了一些修改类方法。

评论