2013-06-12 145 views
2

我遇到了java.util.zip.ZipException:無效的存儲塊長度。無法在jar文件被替換時加載jar文件中的資源

的堆棧跟蹤如下:

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在屬性存在時未能加載?我感謝您的幫助。

回答

5

通常只有在首次需要時才從jar文件中讀取類。

當你當JVM運行時替換的jar文件中,JVM是有這個文件InputStream已經過時了。在這種情況下,如果JAR文件的內容沒有改變,那麼可以從jar中讀取這些類。如果替換的罐子與舊罐子的內容不同,那麼obsolte InputStream將嘗試讀取已知的位置。但是,由於內容已經改變,它可能無法讀取文件。

因此,這個例外

+0

感謝您的回答!這是非常合理的。在JVM停止之前,JVM是否永遠不關閉InputStream? JVM如何判斷jar的內容是否改變? –

2

類重新加載通常通過丟棄舊的類加載器併爲該類的更新版本創建一個新的類加載器來完成。據我所知,無法在同一個類加載器中重新加載更改的類。

重新加載屬性文件是另一個問題。但是,它不能包含在jar中,你將不得不監視文件的變化。在這種情況下,你也不應該使用getResourceAsStream()。

+0

謝謝你的回答!我知道我使用了錯誤的方式進行升級。我不明白爲什麼重新加載屬性可能會失敗。爲什麼它不能包含在jar中? –

1

如果你想更換你的jar文件後使用的getResourceAsStream(字符串),你只需要實現自己的方法ClassLoader.findResource(字符串)

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); 
} 

這將確保正確地重新加載任何資源(即使在一個罐子裏)。

(我仍然不知道確切,但默認的類加載器出現存儲第一個找到的URL,它替換源後無效的連接,但在掌管你的類的類加載器保持不變)

+0

感謝您的回答! –