關于was當中ffdc報告java.util.zip.zipexception: error in opening zip file剖析及解決
問題:
was下ffdc日志目錄中出現如下的錯誤,打開zip檔案錯誤

ffdc exception:java.util.zip.zipexception sourceid:com.ibm.ws.classloader.classloaderutils.adddependents probeid:238 reporter:java.lang.class@7c537c91
java.util.zip.zipexception: error in opening zip file
at java.util.zip.zipfile.open(native method)
at java.util.zip.zipfile.<init>(zipfile.java:114)
at java.util.jar.jarfile.<init>(jarfile.java:133)
at java.util.jar.jarfile.<init>(jarfile.java:70)
at com.ibm.ws.classloader.classloaderutils.adddependents(classloaderutils.java:96)
at com.ibm.ws.classloader.classloaderutils.adddependents(classloaderutils.java:143)
at com.ibm.ws.classloader.classloaderutils.adddependentjars(classloaderutils.java:61)
at com.ibm.ws.classloader.classgraph.<init>(classgraph.java:115)
at com.ibm.ws.classloader.classloadermanager.initialize(classloadermanager.java:202)
at com.ibm.ws.classloader.classloadermanager.<init>(classloadermanager.java:166)
at com.ibm.ws.runtime.component.deployedapplicationimpl.start(deployedapplicationimpl.java:891)
at com.ibm.ws.runtime.component.applicationmgrimpl.startapplication(applicationmgrimpl.java:740)
at com.ibm.ws.runtime.component.applicationmgrimpl.start(applicationmgrimpl.java:2092)
at com.ibm.ws.runtime.component.compositionunitmgrimpl.start(compositionunitmgrimpl.java:437)
at com.ibm.ws.runtime.component.compositionunitimpl.start(compositionunitimpl.java:122)
at com.ibm.ws.runtime.component.compositionunitmgrimpl.start(compositionunitmgrimpl.java:380)
at com.ibm.ws.runtime.component.compositionunitmgrimpl.access$300(compositionunitmgrimpl.java:105)
at com.ibm.ws.runtime.component.compositionunitmgrimpl$cuinitializer.run(compositionunitmgrimpl.java:928)
at com.ibm.wsspi.runtime.component.wscomponentimpl$_asynchinitializer.run(wscomponentimpl.java:349)
at com.ibm.ws.util.threadpool$worker.run(threadpool.java:1527)
那到底是哪個檔案在打開時發生錯誤了呢?一頭霧水了吧,汗。。。估計你會。。。
分析:
1、通過對檔案的排查,确認排除了應用程式中引用jar檔案損壞的可能性以及由于jar檔案權限設定導緻無法讀取的可能性
2、打開跟蹤日志級别進行剖析

application servers > memxxx > logging and tracing > change log detail levels
設定classloaderutils跟蹤級别如下

*=info: com.ibm.ws.classloader.classloaderutils=finest
重新啟動後,在trace.log裡可以發現如下資訊

0000001e classloaderut > adddependents entry
/home/xxx/lib/struts/commons-logging.jar
0000001e classloaderut 3 dependent classpath detected: log4j.jar log4j-core.jar
0000001e classloaderut 3 adding /home/xxx/lib/struts/log4j.jar
/home/xxx/lib/struts/log4j.jar
0000001e ffdcprovider i com.ibm.ws.ffdc.impl.ffdcprovider logincident ffdc1003i: ffdc incident emitted on /usr/ibm/websphere/appserver/profiles/xxx/logs/ffdc/memxxx_f3c3750_08.12.23_16.26.42.85048008.txt com.ibm.ws.classloader.classloaderutils.adddependents 238
0000001e classloaderut 3 warning: could not open /home/xxx/lib/struts/log4j.jar : error in opening zip file
0000001e classloaderut < adddependents exit
0000001e classloaderut 3 adding /home/xxx/lib/struts/log4j-core.jar
/home/xxx/lib/struts/log4j-core.jar
0000001e classloaderut 3 warning: could not open /home/xxx/lib/struts/log4j-core.jar : error in opening zip file
......
/home/xxx/lib/struts/struts.jar
0000001e classloaderut 3 dependent classpath detected: commons-beanutils.jar commons-collections.jar commons-digester.jar commons-logging.jar commons-validator.jar jakarta-oro.jar struts-legacy.jar
0000001e classloaderut 3 adding /home/xxx/lib/struts/jakarta-oro.jar
/home/xxx/lib/struts/jakarta-oro.jar
0000001e classloaderut 3 warning: could not open /home/xxx/lib/struts/jakarta-oro.jar : error in opening zip file
0000001e classloaderut 3 adding /home/xxx/lib/struts/struts-legacy.jar
/home/xxx/lib/struts/struts-legacy.jar
0000001e classloaderut 3 warning: could not open /home/xxx/lib/struts/struts-legacy.jar : error in opening zip file
......
繼續分析:
首先,可以确認的是warning所報的是正确的,因為可以通過确認所依賴的log4j.jar log4j-core.jar jakarta-oro.jar struts-legacy.jar之類的檔案不存在。
其次,這些不存在的包是由誰依賴并需要加載的,通過日志的層次關系可以知道,commons-logging.jar需要log4j.jar log4j-core.jar,struts.jar需要jakarta-oro.jar struts-legacy.jar
這樣唯一的可能就是各自的jar包中meta-inf/manifest.mf裡聲明了這些jar的依賴關系了。
打開commons-logging.jar,發現其中的meta-inf/manifest.mf裡包含了
class-path: log4j.jar log4j-core.jar
打開struts.jar,發現其中的meta-inf/manifest.mf裡包含了
class-path: commons-beanutils.jar commons-collections.jar commons-dig
ester.jar commons-logging.jar commons-validator.jar jakarta-oro.jar s
truts-legacy.jar
于是真相大白了,解決的辦法要麼增加相應版本所依賴的jar包,要麼就是簡單地删除class-path,根據應用程式的需要進行确認并使用之,[color=red]建議用前者進行解決。要麼就更新這些元件包。[/color]
代碼解讀

classloaderutils.java
public static string[] adddependentjars(string paths[])
{
arraylist newpaths = new arraylist(arrays.aslist(paths));
for(int i = 0; i < paths.length; i++)
if(paths[i].tolowercase().endswith(".jar"))
adddependents(paths[i], newpaths);
string result[] = new string[newpaths.size()];
result = (string[])(string[])newpaths.toarray(result);
return result;
}
private static void adddependents(string jarfilename, list classpath)
// ...省略。。。
jar = new jarfile(jarfilename);// 錯誤在這一行
manifest = jar.getmanifest();
attrs = manifest.getmainattributes();
dependents = attrs.getvalue(java.util.jar.attributes.name.class_path);// 擷取依賴包路徑
stringtokenizer tokens = new stringtokenizer(dependents, " ");
do
if(!tokens.hasmoretokens())
break;
string nextdependent = tokens.nexttoken();
string nextdependentfullpath = (new stringbuilder()).append(prefix).append(nextdependent).
if(pathutils.listaddnodup(classpath, nextdependentfullpath))
{
adddependents(nextdependentfullpath, classpath); // 疊代加載之
}
} while(true);
在catch代碼塊中
catch(zipexception ze)
manager.ffdc.log(ze, classloaderutils.class, "com.ibm.ws.classloader.classloaderutils.adddependents", "238" + jarfilename);
if(debugenabled)
tr.debug(tc, (new stringbuilder()).append("warning: could not open ").append(jarfilename).append(" : ").append(ze.getlocalizedmessage()).tostring());
catch(ioexception ioe)
manager.ffdc.log(ioe, classloaderutils.class, "com.ibm.ws.classloader.classloaderutils.adddependents", "246");
tr.debug(tc, (new stringbuilder()).append("warning: i/o exception ").append(jarfilename).append(" : ").append(ioe.getlocalizedmessage()).tostring());
}
不厚道,在manager.ffdc.log裡把jarfilename也列印出來,就更容易知道是什麼問題了。
可見列印出有意義的資訊對于分析問題是多少的重要。。。
附帶資訊:将commons-logging.jar與struts.jar與spring 2.5.5釋出所帶的包進行對比分析,發現spring帶的commons-logging.jar包沒有帶有class-path這個條目。

manifest-version: 1.0
created-by: apache ant 1.5.1
extension-name: org.apache.commons.logging
specification-vendor: apache software foundation
specification-version: 1.0
implementation-vendor: apache software foundation
implementation-version: 1.0.3
class-path: log4j.jar log4j-core.jar
對比

archiver-version: plexus archiver
created-by: apache maven
built-by: dlg01
build-jdk: 1.4.2_16
implementation-title: commons logging
implementation-vendor-id: org.apache
implementation-version: 1.1.1
specification-title: commons logging
x-compile-source-jdk: 1.2
x-compile-target-jdk: 1.1
extension-name: org.apache.commons.logging
注意實作的版本問題是不同的
struct.jar包的條目内容不同

extension-name: struts framework
specification-title: struts framework
specification-version: 1.1
implementation-title: struts framework
implementation-version: 1.1
class-path: commons-beanutils.jar commons-collections.jar commons-dig
ester.jar commons-logging.jar commons-validator.jar jakarta-oro.jar s
truts-legacy.jar

ant-version: apache ant 1.6.1
created-by: 1.3.1_04-b02 (sun microsystems inc.)
specification-vendor: the apache software foundation
specification-version: 1.2.9
implementation-vendor: the apache software foundation
implementation-version: 1.2.9
class-path: commons-beanutils.jar commons-digester.jar commons-fileup
load.jar commons-logging.jar commons-validator.jar jakarta-oro.jar
也要注意實作的版本問題是不同的