抠腚爱揉曼 Coding Iron Man

30Jun/105

啊啊,hessian你为什么要这样

Posted by Anson

公司有一个服务框架提供分布式调用支持的,其中序列化用的是hessian,而且是较早的3.0.13(现在hessian都5.X了,但因为那个服务框架太基础了,绝大多数核心应用都在用,所以不敢随便换)。这个版本的hessian有个很囧的bug,在反序列化StackTraceElement的时候有两段无用代码,其中有一段无用代码成了bug的源头。

这个bug的表现形式是这样的当你反序列化一个对象,它有StackTraceElement,并且有两个或以上==的对象包含其中的话,就可能会报错。

StackTraceElementDeserializer是hessian用来反序列化StackTraceElement的执行器,其中有段代码是这样的。

    HashMap map = new HashMap(); //new了一个空的HashMap出来
    in.addRef(map); // 加到反序列化的refList中

hessian有一个refList,用来存放已经被反序列化过的对象,后面出现同一对象的时候在序列化流中用R index直接从refList中读取从而提高效率。在上面那段莫明的代码中,每次StackTraceElementDeserializer的readMap被调用就会往refList中插入一个无用的HashMap,从而导致后面所有的refList和反序列化流中的index就对不上了,当通过index读取ref来构造对象的时候就会出现类型转换等各种各样的错误。

这个类里还有一段不明所以的代码。

    Throwable e1 = new IOException();
    try {
      throw e1;
    } catch (Throwable e2) {
      e1 = e2;
    }

不知道干什么的……貌似没有造成任何别的影响……无视……

Tagged as: , 5 Comments
23Jun/105

实现中用到ApplicationContextAware机制spring单元测试冲突的解决

Posted by Anson

先搬篇东西过来 以前为了贡献给搜索引擎发在了javaeye上 搬过来……

这个问题纠结了我比较久,而且google不到答案,今天看了下spring相关部分的代码,终于解决了,所以记录一下。

先说下场景~

1. 程序中有一个singleton的class实现ApplicationContextAware来获取spring支持,这里称为ss(spring support or spring scheduler or spring suibian……)好了。

2. 单元测试依赖spring都基于AbstractDependencyInjectionSpringContextTests来玩。

3. 多组单元测试跑到的代码都会用到ss来获取spring支持。

spring单元测试基类会把你所有的配置文件location字串拼起来作为key来cache一个解析好的applicationContext。

于是假设我有4个单元测试类,分为2组,1、2的配置文件是a.xml,3、4的配置文件是b.xml。我跑这4个单元测试类的时候可能会出现1-3-2-4这样的顺序(不知道排序规则是什么……)。

因为spring的cache,它只在1、3的时候会分别解析a.xml和b.xml两个配置文件并初始化ss,为ss注入applicationContext;而跑2、4的时候则是直接从cache中获取applicationContext。

这样就会导致我在跑2的时候,ss中被注入的applicationContext仍然是b.xml的(因为2并不reload config,也就不会重新初始化ss和注入applicationContext),然后2的单元测试就会发现从ss中获取不到需要的bean。

这么看来,有两个解决办法。一个是让他们都用一样的配置文件,这样显然不太爽。另一个就是想办法让ss中的applicationContext和spring单元测试容器中的applicationContext同步。

解决方法其实很简单,覆盖spring单元测试基类的prepareTestInstance()方法,用this.applicationContext直接干掉ss中的applicationContext就行了……