具体场景
最近项目中基于jarslink做实时算法的加载,为了方便jar包更新测试,我们把jar包开发完后以snapshot版本推送到maven中央仓库中。jarslink查询器根据配置动态从maven仓库加载算法jar包及其依赖。为了在jar包发生改变时动态刷新,代码中农将对应jar包的md5作为版本version的一部分。在代码发生修改时,重新推送jar包到maven仓库,代码中的maven加载器动态刷新插件jar包,并重新加载子容器,此时意外发生了,jvm crash,多次试验,java虚拟机不是crash就是报ClassNotFoundException,原因为何?这就是本文要说的:不要在java虚拟机运行时替换正在使用的jar包!
具体原因探索
既然jar包名称和原来的一模一样,jar包里面的类也一致,为什么jvm就加载不到这个jar包里面的类呢?要回答这个问题,我们可以先通过lsof来查看一下某个java进程打开的文件句柄:
lsof | grep java 6213
我们可以看到,这个java进程维护了多个jar包文件的句柄。通过这个,我们可以想到应该是jvm在运行中维护了这些jar包的inputstream,在需要某个类的时候,就从这些inputstream中获取某个类的字节码然后加载。这个维护的inputstream是针对原先旧jar包打开的输入流,如果这时