使用dom4j发现的一个问题

在使用dom4j时碰到一个ClassCastException问题:org.dom4j.DocumentFactory不能转换为org.dom4j.DocumentFactory。

同一个类不能相互转换,一般是由于这是两个分别由不同类加载器加载的类的缘故。

检查发现,在一个webapp下和tomcat的shared目录下均存在dom4j的包,因此这两个类应该是分别从这两个包中加载的。

为什么会从两个地方的jar包分别加载同一个类呢?这有点奇怪,于是看了下dom4j的源码,发现问题在DocumentFactory的加载机制上。

DocumentFactory的实现类可以由用户自己指定,因此程序中选择通过ContextClassLoader进行加载,这是合理的,用户指定的类应该是可以通过当前线程的加载器加载。

问题出在:在share中的一个类使用到了dom4j,于是share加载了dom4j中的所有类。

而ContextClassLoader是webapp加载器,于是又从webapp中加载了一次DocumentFactory,并创建实现。

该实现再使用显示转换成share所加载的DocumentFactory类的实例,这样就发生异常了。

 

解决方法:

1.当然是只在一个地方放置dom4j的包。

2.这种情况不能完全避免,因此也可以在使用dom4j是显示地设置DocumentFactory实例,这样程序就不会再去加载该类了。

3.其实dom4j本身也可以改进一下,检查到用户指定的类以org.dom4j.开头则由当前加载器加载,其他的才通过ContextClassLoader进行加载。

 

扩展:

在程序中使用到ContextClassLoader加载类的地方也都最好进行检查,如果属于本jar包中的类则改用当前加载器加载。

 

posted on 2012-05-12 12:20  我本少年  阅读(2280)  评论(2编辑  收藏  举报