简体   繁体   English

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

[英]Failed to load resources in jar file when jar file is replaced

I meet java.util.zip.ZipException: invalid stored block lengths. 我遇到java.util.zip.ZipException:存储的块长度无效。

The stack trace is as following: 堆栈跟踪如下:

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)

This happens when my project try to upgrade. 当我的项目尝试升级时会发生这种情况。 The upgrade logic is to replace old jar files with new ones, and JVM is still running. 升级逻辑是用新的jar文件替换旧的jar文件,JVM仍然在运行。

There is jar file(jarA.jar) includes a property file, and property file records some full class names. jar文件(jarA.jar)包含属性文件,属性文件记录一些完整的类名。 These class names will be used to create instance by reflection. 这些类名将用于通过反射创建实例。 The upgrade logic try to load the property file with SystemClassLoader.getResourceAsStream(). 升级逻辑尝试使用SystemClassLoader.getResourceAsStream()加载属性文件。

If the jar file(jarA.jar) is replaced with new one, and the content of property is changed, this Exception will happen. 如果jar文件(jarA.jar)被替换为新文件,并且属性的内容发生了更改,则会发生此异常。 Seems SystemClassLoader can not load the property correctly. 似乎SystemClassLoader无法正确加载属性。

The project is compiled by java1.4, and running on jre1.7, Os is Windows. 该项目由java1.4编译,并在jre1.7上运行,Os是Windows。

Does any one can explain why SystemClassLoader failed to load while the property exists? 有没有人可以解释为什么SystemClassLoader在属性存在时无法加载? I appreciate your help. 我感谢您的帮助。

Usually classes are read from jar files only when it is first time required. 通常只有在第一次需要时才从jar文件中读取类。

When you replace the jar files when JVM is running, the file InputStream the JVM was having has become obsolete. 当JVM运行时替换jar文件时,JVM所具有的文件InputStream已经过时了。 In this case, if the content of the JAR file is not changed, then the classes can be read from the jar. 在这种情况下,如果未更改JAR文件的内容,则可以从jar中读取类。 If the replaced jar has different content than the old jar, then the obsolte InputStream will try to read in the position that is known to it. 如果替换的jar具有与旧jar不同的内容,则obsolte InputStream将尝试读取其已知的位置。 But, since the conent has changed, it may not be able to read the file. 但是,由于conent已更改,因此可能无法读取文件。

Hence this exception 因此这个例外

Class reloading is usually done by throwing away the old classloader and creating a new one for the updated versions of the class. 类重新加载通常是通过丢弃旧的类加载器并为类的更新版本创建新的类加载器来完成的。 As far as I know there is no way to reload a changed class within the same classloader. 据我所知,无法在同一个类加载器中重新加载更改的类。

Reloading of a property file is another problem. 重新加载属性文件是另一个问题。 But then it must not be included in the jar and you will have to monitor changes of the file. 但是它不能包含在jar中,你必须监视文件的变化。 You shouldn't use getResourceAsStream() in that case, also. 在这种情况下,您也不应该使用getResourceAsStream()。

If you want to use getResourceAsStream(String) after replacing your jar files, you just have to implement your own method ClassLoader.findResource(String) 如果要在替换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);
}

It will assure a proper reloading of any resource (even if in a jar). 它将确保正确地重新加载任何资源(即使在jar中)。

(I'm still not sure exactly, but the default classloader appears to store a connection to the first found URL, which invalidates after replacing the source, but remains unchanged in the classloader in charge of your classes) (我仍然不确定,但是默认的类加载器似乎存储了与第一个找到的URL的连接,它在替换源后失效,但在负责类的类加载器中保持不变)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM