研究类加载问题的心得

[问题的起因]

对于FTPC比较早的版本,我们对于Fix的测试经常是通过替换安装后的目录中的class文件,这样我们就无需下载整个工程,达到测试的目的,而且这种测试还比较准确。 今天在做对于PO81MR12d的一个Fix(PC-13877)的测试的时候,我仍然采用替换class文件的方式来测试。 一开始我们发现只需要修改一个CoreEJB中文件即可,所以我替换了这个class文件,测试很快就生效了。 后来我们发现Fix有些问题,需要修改SharedObject中的三只类文件, 所以我就拿修改后的类文件去替换DSPlantOperations.ear中的SharedObjects.jar中的类文件,替换后,重启AppServer,发现测试怎么都无法生效。

 

[解决之路]

这个问题困恼了我一段时间,想想不应该啊,于是Ken,Roy和我一起思考如何解决这个奇怪的问题:

一开始 我们怀疑是由于JBoss的缓存文件导致我们的修改没有生效,所以我们尝试每次启动前,清理缓存,可是这样做以后,问题仍然没有解决,很明显不是这个原因。

然后 我们就想我们修改的类在PlantOpsJavaProxies-JBoss.jar和SharedObjects.jar中都有,会不会因为PlantOpsJavaProxies-JBoss.jar惹得祸,可是最后的验证否定了我们的猜测。

最后 我们想,既然确定类文件有修改,那么没有生效就一定是App Server运行的时候没有使用我们修改的文件所在的jar(SharedObjects.jar),于是我们决定直接删除SharedObjects.jar中我们需要修改的类,想看看是否报错,以此来证明App Server运行的时候到底有没有使用我们修改的这个jar。 测试后发现,问题仍然存在,这证明我们的猜测是正确的,App Server运行的时候确实没有使用我们修改的jar。而这个jar看起来是名正言顺的应该被使用,因为它所在的目录看起来很像。

这个猜测的验证迅速抛出一个问题:既然没有用这个SharedObjects.jar,那到底用哪里的SharedObjects.jar?

 

为此我们找遍了DSPlantOperations.ear, 都没有发现其它的SharedObjects.jar。这就有些奇怪了。但最后我们在DSDataManagement.ear 中找到了SharedObjects.jar,删除DSDataManagement.ear,我们的测试顺利通过了。

 

这个问题解决让我们认识到了对于早期的版本,比如PO81,由于发布的EAR中含有DSDataManagement.ear, 而这个EAR中有和DSPlantOperations.ear中一样的JAR: SharedObjects.jar, 所以在类加载的时候,一样的class只会加载一个,而至于哪一个会被加载,我们先看看下面的理论:

 

类加载采用了cache机制,也就是如果 cache中保存了这个Class就直接返回它,如果没有才从文件中读取和转换成Class,并存入cache,这就是为什么我们修改了Class但是必须重新启动JVM才能生效的原因。

每个ClassLoader加载Class的过程是:
1.检测此Class是否载入过(即在cache中是否有此Class),如果有到8,如果没有到2
2.如果parent classloader不存在(没有parent,那parent一定是bootstrap classloader了),到4
3.请求parent classloader载入,如果成功到8,不成功到5
4.请求jvm从bootstrap classloader中载入,如果成功到8
5.寻找Class文件(从与此classloader相关的类路径中寻找)。如果找不到则到7.
6.从文件中载入Class,到8.
7.抛出ClassNotFoundException.
8.返回Class.

 

关于更多类加载的内容请参照各大搜索网站。

 

[根本原因]

在发布的EAR中: DSPlantOperations.ear和DSDataManagement.ear有两个一样的JAR: SharedObjects.jar, 而我们的修改没有生效就是因为JVM运行的时候加载的不是我们修改的jar中的类。

你可能感兴趣的:(ClassLoader,cache,server,测试,jar,Class)