【问题标题】:WAS 6.1 java.lang.VerifyError: class loading constraint violatedWAS 6.1 java.lang.VerifyError:违反了类加载约束
【发布时间】:2011-02-21 03:40:24
【问题描述】:

环境是 Linux 上的 WAS 6.1,部署一个 webapp,使用 来自 xercesImpl.jar 的类。

由于公司政策限制,该应用必须部署 设置:

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 仍然得到相同的错误(不是 类NotFoundException)。因此 WAS 似乎正在解决参考 使用与我们的参考文献不兼容的自己的副本 编译的类文件。但是,“xercesImpl.jar”的唯一其他实例 我可以找到(与我们的应用程序一起部署的副本除外)在目录中 deploytool,好像在应用服务器之外。

我用

扫描了 WAS 中的所有罐子(全部 1300 个)
for i in `find . -name \*.jar`; do jar tvf $i|grep -qi xerces && echo $i ; done

发现./java/jre/lib/xml.jar包含了org.apache.xerces.*中的所有类, 所以这很可能是类加载器解析引用的地方。

这是奇怪的部分:

如果我们更改为“先加载父类加载器”,我们不会看到异常。 这与预期的行为背道而驰。我们希望与 “应用程序类加载器优先”它将使用我们的 xercesImpl.jar 提供,并且仅当我们设置“父类加载器”时才使用 WAS 的版本 首先”。这似乎与我们实际看到的相反。

问题:

类加载器委托设置如何与上述信息交互以产生观察到的行为?

【问题讨论】:

  • 这听起来不错。如果我理解你的话,问题不在于 DocumentBuilderImpl,而是在 WAR 中找到它引用的类之一时,它正在从 JDK 中解决。这不能解释为什么当我们在 WAR 中包含 xercesImpl.jar 时,我们仍然会得到完全相同的错误,引用相同的方法和类名。你是说消息中引用的方法和类名与问题无关?

标签: java websphere classloader verifyerror


【解决方案1】:

您的 WAR 还包括 org.xml.sax 或 org.w3c.dom 类,然后您引用的应用程序外部的类也引用了这些类。这设置了一个场景,您的应用程序类加载器可以看到同一类的两个实例,这是一个链接错误。

例如,如果您的应用程序使用 javax.xml.bind.Unmarshaller.unmarshal(InputSource),那么 Unmarshaller 将从 JDK 加载,并且 Unmarshaller 类仅对 JDK InputSource 可见。当您的应用程序创建其 InputSource 时,它​​将从 WAR 加载类(因为“应用优先”策略),然后您的应用程序将尝试将 WAR InputSource 的实例传递给 JDK Unmarshaller,后者只能接受JDK 输入源。

有两种解决方案:

  1. 从您的应用程序中删除所有 API jar,并使用 JDK 中的那些。例如,删除包含 org.xml.sax 或 org.w3c.dom 的 jar。
  2. 在您的 WAR 中包含所有引用您要引用的类的库。例如,在您的 WAR 中包含 JAXB 库的副本。

根据我的经验,链接错误很难追踪,因为 JVM 提供了关于导致添加链接的原因的糟糕信息。我通常启用类加载器跟踪,重现问题,然后向后走,直到找到从应用程序外部加载的类,“听起来”它可能引用了已知存在于应用程序内的类。

【讨论】:

  • 这听起来不错。如果我理解你的话,问题不在于 DocumentBuilderImpl,而是在 WAR 中找到它引用的类之一时,它正在从 JDK 中解决。这不能解释为什么当我们在 WAR 中包含 xercesImpl.jar 时,我们仍然会得到完全相同的错误,引用相同的方法和类名。你是说消息中引用的方法和类名与问题无关?
  • 谢谢。通过一些研究,我能够通过从我们的应用程序中删除几个不必要的 jar 来解决问题,这些 jar 是在 JDK 包括 org.xml.sax 和 org.w3c.dom 之前遗留下来的。我还发现了一个冲突的 DataSource 定义。
  • 是的,DocumentBuilderImpl 与问题无关。 parse 方法恰好适用于有链接问题的引用类型。就像我说的,JVM 提供了糟糕的信息;我应该更大胆地说“有时会误导”:-)。
  • 修复我的情况:将 provides 添加到 maven 依赖项 jaxb-api。
【解决方案2】:

我们的问题是在 WAS 8.5 上部署。

在我们的 Web 应用程序中,我们有一个由 cxf 生成的 Web 服务客户端。没有问题。

当我们在 tika-parser 中添加用于 mime 类型检测时,我们遇到了这个问题。

我们排除了三个依赖项:

<dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-parsers</artifactId>
            <version>${apache.tika.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>geronimo-stax-api_1.0_spec</artifactId>
                    <groupId>org.apache.geronimo.specs</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>xercesImpl</artifactId>
                    <groupId>xerces</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>xmlbeans</artifactId>
                    <groupId>org.apache.xmlbeans</groupId>
                </exclusion>
            </exclusions>
        </dependency>

一旦它们被排除,我们的应用程序就会成功启动。

【讨论】:

    【解决方案3】:

    可能为时已晚,但我们解决了这个问题,删除了 server.xml 中的这一行:

    jaxb-2.1

    【讨论】:

      【解决方案4】:

      禁用字节码验证

      java.lang.VerifyError - 运行时未经检查的异常 一旦类文件加载到Websphere JVM中,接下来就是字节码校验。在字节码校验过程中,如果我们的类违反了JVM约束,就会出现这个错误。

      禁用字节码验证。去

      管理控制台-&gt;server1-&gt;java 和进程管理-&gt;process definition-&gt;JVM 参数`

      并且在 JVM 参数中传递以下字符串

       -Xverify:none 
      

      然后在工作区中打开 ApplicationDeploymentDescriptor xml 文件,转到部署选项卡,选择 PARENT_LAST 进行战争,以及第一个选项。这将停止 xml 验证错误。

      【讨论】:

        【解决方案5】:

        如果我们改为“父类加载器 首先”我们没有看到例外。 这与预期背道而驰 行为。

        是的,这是正确的,这是您看到此类行为的唯一方法。我可以建议你看看“你真的得到类加载器吗?”说话,因为您的问题没有单一或简短的答案。

        http://www.slideshare.net/guestd56374/do-you-really-get-class-loaders http://www.parleys.com/#sl=2&st=5&id=1585

        【讨论】:

        • 这真的更像是在推销你的产品,不是吗?
        • 是的,答案是正确的,“parent last”是看到这个问题的唯一方法。不幸的是,该链接没有帮助,并且有几个不准确之处。幻灯片 8:JavaEE 规范既不要求最后的父 CL,也不要求单独的 CL。幻灯片 11:ClassNoDefFoundException 不是真正的异常类型;该方法是“getURLs”。我不再照顾那件事了。修复,我将删除反对票。
        • @Jim 嗯?简介中有两张幻灯片。该演讲专门针对解决类似问题。 @bkail 不是我关心你如何投票,而是看 Servlet 规范 SRV.9.7.2。谢谢你的错别字,我通常会做很多演示,所以幻灯片并不是很重要。
        猜你喜欢
        • 2014-04-10
        • 1970-01-01
        • 1970-01-01
        • 2018-07-17
        • 1970-01-01
        • 1970-01-01
        • 2018-09-29
        • 2011-04-15
        • 2015-07-13
        相关资源
        最近更新 更多