搜索
您的当前位置:首页正文

Java变量引用BUG

来源:二三娱乐

Bug描述

CoaOperServiceBO这个类中caoCache定义为私有的,修改缓存的方法没有被任何方法调用,但是莫名其妙造成coaCache被修改。

public class CoaOperServiceBO{
  private Map coaCache = new HashMap();
  public CoaDto getCoabyID(String coa_id) throws CoaException {
    // zwh20141009key值中增加区划
    CoaDto coaDto = null;
    if (coaCache.get(getKeyRgSetYear() + coa_id) != null) {
      coaDto = (CoaDto) coaCache.get(getKeyRgSetYear() + coa_id);
    } else {
      // 调用平提供的COA服务得到COA对象
      UtilCache.removeCoaById(coa_id);
      XMLData coaData = glcoa.getCoabyID(coa_id);
      // coaDto = XMLdataToCoaObj(coaData);
      // 把平台提供的对象转换为统一对外提供的COA对象
      if (coaData != null) {
        coaDto = ChangeXMLdataToCoaObj(coaData);
        coaCache.put(getKeyRgSetYear() + coa_id, coaDto);
      }
    }
    relatedElementDAO.replaceCoaAllEleName(coaDto.getCoaDetail());
    //返回克隆对象,防止上层数据修改
    return  cloneCoaDto(coaDto);
  }
...
}

发现

后面发现,将缓存中引用的对象直接放回给上一层。这样子,上层就相当于直接修改缓存了。然而上一层是不知道的,并且该类也有专门修改缓存的方法,逻辑思维上也不能通过上面这个方法直接修改缓存。于是通过查找方法的调用,具体找到了修改的地方。通过代码逻辑也确实是上层不清楚,导致缓存被修改。

解决方法

方案一
通过clone对象的方法,返回对象的副本,而不是直接返回缓存中指向的对象,这样调用者修改就不会造成缓存也被修改。这种适合处理不是特别复杂的对象

方案二
也是返回对象的副本,但是通过序列化转成字节流,再将字节流转为对象。这种适合处理比较复杂的对象

总结

这个bug看上去简单,但是稍不注意。如果遇到了复杂逻辑嵌套,就比如这次,我是在调用第4层才找到的,总共差不多找了300多个调用方法。所以慎用缓存
然后Java中也是有不可变集合的,可以考虑使用

Top