WAS 6.1 java.lang.VerifyError:违反了类加载约束
Linux上的环境是WAS 6.1,部署了一个使用xercesImpl.jar类的webapp。
由于公司政策限制,必须使用以下设置部署应用:
Class Loader Order Classes loaded with parent class loader first -> Classes loaded with application class loader first WAR class loader policy Class loader for each WAR file in application -> Single class loader for application
WAR文件包含xercesImpl.jar的副本,与编译应用程序时类路径中的相同。
在启动webapp时,当Spring尝试解析其配置时,它会抛出:
java.lang.VerifyError: class loading constraint violated (class: org/apache/xerces/jaxp/DocumentBuilderImpl method: parse(Lorg/xml/sax/InputSource;)Lorg/w3c/dom/Document;)
因此分析
看来WAS提供了org.apache.xerces.jaxp.DocumentBuilderImpl的实现,因为我们可以从WAR文件中删除xercesImpl.jar并仍然得到相同的错误(不是ClassNotFoundException)。 因此,WAS似乎使用自己的副本解析引用,该副本与我们编译的类文件中的引用不兼容。 但是,我可以找到的’xercesImpl.jar’的唯一其他实例(除了使用我们的应用程序部署的副本)位于目录deploytool
,它似乎位于应用服务器之外。
我用WAS(所有1300个)扫描了所有的jar子
for i in `find . -name \*.jar`; do jar tvf $i|grep -qi xerces && echo $i ; done
并发现./java/jre/lib/xml.jar
包含org.apache.xerces.*
中的所有类,因此这可能是类加载器解析引用的地方。
这是肮脏的部分:
如果我们改为“父类加载器优先”,我们看不到exception。 这与预期的行为背道而驰。 我们希望使用“application classloader first”,它将使用我们提供的xercesImpl.jar,并且只有在我们设置“父类加载器优先”时才使用WAS的版本。 这看起来与我们实际看到的情况相反。
问题:
类加载器委托设置如何与上述信息交互以产生观察到的行为?
您的WAR还包括org.xml.sax或org.w3c.dom类,然后您引用的应用程序之外的类也引用了这些类。 这将设置一个场景,您的应用程序类加载器可以看到同一个类的两个实例,这是一个链接错误。
例如,如果您的应用程序使用javax.xml.bind.Unmarshaller.unmarshal(InputSource),则将从JDK加载Unmarshaller,而Unmarshaller类仅具有JDK InputSource的可见性。 当您的应用程序创建其InputSource时,它将从WAR加载类(因为“app first”策略),然后您的应用程序将尝试将WAR InputSource的实例传递给JDK Unmarshaller,它只接受一个实例JDK InputSource。
有两种解决方案:
- 从应用程序中删除所有API jar,并使用JDK中的API jar。 例如,删除包含org.xml.sax或org.w3c.dom的jar。
- 在WAR中包含引用要引用的类的所有库。 例如,在WAR中包含JAXB库的副本。
根据我的经验,链接错误很难追踪,因为JVM提供了关于导致链接添加的原因的糟糕信息。 我通常启用类加载器跟踪,重现问题,然后向后走,直到我发现从应用程序外部加载的类“听起来像”它可能引用已知存在于应用程序内的类。
我们的问题是在WAS 8.5上部署。
在我们的Web应用程序中,我们有一个由cxf生成的Web服务客户端。 没有问题。
当我们在tika-parser中添加mime类型检测时,我们就遇到了这个问题。
我们排除了三个依赖项:
org.apache.tika tika-parsers ${apache.tika.version} geronimo-stax-api_1.0_spec org.apache.geronimo.specs xercesImpl xerces xmlbeans org.apache.xmlbeans
一旦他们被排除,我们的申请就会成功开始。
可能为时已晚,但我们解决了这个问题,在server.xml中删除了这一行:
JAXB-2.1
禁用字节码validation
java.lang.VerifyError –运行时未经检查的exception一旦在Websphere JVM中加载了类文件,那么字节代码变换就是下一个进程。如果我们的类违反了JVM约束,则会出现字节代码validation,然后会出现此错误。
禁用字节码validation。 去
管理控制台->
server1 ->
java和进程管理->process definition->
JVM参数`
在JVM参数中传递以下字符串
-Xverify:none
并在工作区中打开ApplicationDeploymentDescriptor xml文件,转到部署选项卡,选择PARENT_LAST for war,以及第一个选项。 这会停止xmlvalidation错误。
如果我们改为“父类加载器优先”,我们看不到exception。 这与预期的行为背道而驰。
是的,这是正确的,这是你能看到这种行为的唯一方法。 我可以建议你看看“你真的得到class级装载机吗?” 谈话,因为你的问题没有单一或简短的答案。
http://www.slideshare.net/guestd56374/do-you-really-get-class-loaders http://www.parleys.com/#sl=2&st=5&id=1585