更换jar文件时无法在jar文件中加载资源

时间:2013-06-12 07:57:10

标签: java

我遇到java.util.zip.ZipException:存储的块长度无效。

堆栈跟踪如下:

Caused by: java.util.zip.ZipException: invalid stored block lengths
at java.util.zip.InflaterInputStream.read(Unknown Source)
at java.io.FilterInputStream.read(Unknown Source)
at java.io.FilterInputStream.read(Unknown Source)
at java.util.Properties$LineReader.readLine(Unknown Source)
at java.util.Properties.load0(Unknown Source)
at java.util.Properties.load(Unknown Source)

当我的项目尝试升级时会发生这种情况。升级逻辑是用新的jar文件替换旧的jar文件,JVM仍然在运行。

有jar文件(jarA.jar)包含属性文件,属性文件记录一些完整的类名。这些类名将用于通过反射创建实例。 升级逻辑尝试使用SystemClassLoader.getResourceAsStream()加载属性文件。

如果jar文件(jarA.jar)被替换为新文件,并且属性的内容发生了更改,则会发生此异常。似乎SystemClassLoader无法正确加载属性。

项目由java1.4编译,在jre1.7上运行,Os是Windows。

是否有人可以解释为什么SystemClassLoader在属性存在时无法加载?我感谢您的帮助。

3 个答案:

答案 0 :(得分:5)

通常只有在第一次需要时才从jar文件中读取类。

当JVM运行时替换jar文件时,JVM所拥有的文件InputStream已经过时了。在这种情况下,如果未更改JAR文件的内容,则可以从jar中读取类。如果替换的jar具有与旧jar不同的内容,则obsolte InputStream将尝试读取其已知的位置。但是,由于conent已更改,因此可能无法读取文件。

因此这个例外

答案 1 :(得分:2)

类重新加载通常是通过丢弃旧的类加载器并为类的更新版本创建新的类加载器来完成的。据我所知,无法在同一个类加载器中重新加载更改的类。

重新加载属性文件是另一个问题。但是它不能包含在jar中,你必须监视文件的变化。在这种情况下,你也不应该使用getResourceAsStream()。

答案 2 :(得分:1)

如果要在替换jar文件后使用getResourceAsStream(String),则只需实现自己的方法ClassLoader.findResource(String)

public URL findResource(final String name) {
    // find URL (and cache it if necessary (Hashtable ?))
    // do not call super.findResource(String)
    return url; // in a jar: new URL("jar:jar-path!/" + name);
}

它将确保正确重新加载任何资源(即使在jar中)。

(我仍然不确定,但是默认的类加载器似乎存储了与第一个找到的URL的连接,它在替换源后失效,但在负责类的类加载器中保持不变)