2

我遇到 java.util.zip.ZipException: invalid stored block lengths。

堆栈跟踪如下:

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文件,JVM还在运行。

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

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

项目采用java1.4编译,运行在jre1.7上,os为windows。

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

4

3 回答 3

5

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

当您在 JVM 运行时替换 jar 文件时,JVM 拥有的文件InputStream已过时。在这种情况下,如果 JAR 文件的内容未更改,则可以从 jar 中读取类。如果被替换的 jar 与旧 jar 的内容不同,那么过时的 jarInputStream将尝试在它已知的位置读取。但是,由于内容已更改,它可能无法读取该文件。

因此这个例外

于 2013-06-12T08:42:26.997 回答
2

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

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

于 2013-06-12T08:15:38.897 回答
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 的连接,该 URL 在替换源后失效,但在负责您的类的类加载器中保持不变)

于 2013-06-12T15:26:16.297 回答