WAS 6.1 java.lang.VerifyError:违反了类加载约束

发布于 2024-09-01 16:46:32 字数 1416 浏览 3 评论 0原文

环境是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 的副本,与 编译应用程序时位于类路径中。

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

我扫描了WAS中的所有jar(总共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的版本 第一”。这似乎与我们实际看到的相反。

问题:

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

The environment is WAS 6.1 on Linux, deploying a webapp that uses
classes from xercesImpl.jar.

Due to company policy restrictions, the app must be deployed with
settings:

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

The WAR file contains a copy of xercesImpl.jar, the same one that
was in the classpath when the app was compiled.

When launching the webapp, when Spring tries to parse its configs, it
throws:

java.lang.VerifyError: class loading constraint violated 
    (class: org/apache/xerces/jaxp/DocumentBuilderImpl 
    method: parse(Lorg/xml/sax/InputSource;)Lorg/w3c/dom/Document;)

ANALYSIS SO FAR

It appears that WAS provides an implementation of
org.apache.xerces.jaxp.DocumentBuilderImpl, because we can remove
xercesImpl.jar from the WAR file and still get the same error (not
ClassNotFoundException). Thus WAS seems to be resolving the references
using its own copy that is incompatible with the references in our
compiled class files. However, the only other instance of 'xercesImpl.jar'
I can find (other than the copy deployed with our app) is in directory
deploytool, which seems to be outside the app server.

I scanned all the jars in WAS (all 1300 of them) with

for i in `find . -name \*.jar`; do jar tvf $i|grep -qi xerces && echo $i ; done

and found that ./java/jre/lib/xml.jar contains all the classes in org.apache.xerces.*,
so this is likely where the classloader is resolving the reference.

HERE'S THE WEIRD PART:

If we change to "parent class loader first" we do not see the exception.
This goes counter to the expected behavior. We would expect that with
"application classloader first" it would use the xercesImpl.jar that we
provided, and use WAS's version only if we set "parent classloader
first". This appears to be backwards from what we actually see.

THE QUESTION:

How is the classloader delegation setting interacting with the above information to result in the observed behavior?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

雨后彩虹 2024-09-08 16:46:32

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

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

有两种解决方案:

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

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

Your WAR is also including either org.xml.sax or org.w3c.dom classes, and then you're referencing a class that is outside your application that also references these classes. This sets up a scenario where your application class loader has visibility to two instances of the same class, which is a linkage error.

For example, if your application uses javax.xml.bind.Unmarshaller.unmarshal(InputSource), then Unmarshaller would be loaded from the JDK, and the Unmarshaller class only has visibility to the JDK InputSource. When your application creates its InputSource, it will load the class from the WAR (because "app first" policy), and then your application would attempt to pass an instance of the WAR InputSource to the JDK Unmarshaller, which can only accept an instance of the JDK InputSource.

There are two solutions:

  1. Remove all API jars from your application, and use the ones from the JDK. For example, remove the jar containing org.xml.sax or org.w3c.dom.
  2. Include all libraries in your WAR that reference the classes you want to reference. For example, include a copy of the JAXB library in your WAR.

In my experience, linkage errors are quite difficult to track down because JVMs give lousy information about what causes linkages to be added. I usually enable class loader trace, reproduce the problem, and then walk backwards until I find a class loaded from outside the application that "sounds like" it might reference a class that is known to exist inside the application.

眼趣 2024-09-08 16:46:32

我们的问题是在 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>

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

Our issue was deploying on WAS 8.5.

In our web application we have a web service client generated by cxf. No issues.

When we added in tika-parser for mime type detection, then we got this issue.

We excluded three dependencies:

<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>

Once they were excluded, our application started successfully.

很酷不放纵 2024-09-08 16:46:32

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

jaxb-2.1

May be it's too late but, we solved this problem, removing this line in server.xml:

jaxb-2.1

瀟灑尐姊 2024-09-08 16:46:32

实际情况如下:

应用程序的 pom.xml 文件和 WAS 上的 server.xml 文件中都定义了相同的库。因此,在 WAS 从应用程序的 pom.xml 文件创建的 war 文件加载类后,它会尝试从 server.xml 文件中指定的 WAS 上的共享库中的库加载相同的类。

如果您的应用程序被命名为 corrservo65-01,则将为应用程序在由如下路径定义的文件夹中定义 server.xml 文件:

/usr/WebSphere905/AppServer/profiles/node01/config/cells/dwauslwasapp06Cell01/nodes/dwauslwasapp06Node01/servers /corrservo65-01

您可以通过在 server.xml 文件中搜索 classloaders 元素来查看还从共享库加载哪些库。 classloaders 元素内部有libraries 元素。每个都定义一个库,ALSO从 WAS 上的共享库以及应用程序的 pom.xml 文件中定义的库加载。

例如,wsdl4j-1.6.2 在 pom.xml 文件中定义为依赖项:

 <dependency>
    <groupId>wsdl4j</groupId>
    <artifactId>wsdl4j</artifactId>
    <version>1.6.2</version>
</dependency>

下面是 WAS 从共享库加载的同一个库:

<classloaders xmi:id="Classloader_1629835928681" mode="PARENT_LAST">
   <libraries xmi:id="LibraryRef_1629835942246" libraryName="wsdl4j-1.6.2"/>
</classloaders>

当您在 WAS 中将应用程序设置为parent_last 时,您还必须删除也可以从中引用共享库中找到的库。然后,您需要将这些库包含在应用程序的 pom.xml 文件中。这将导致基于 pom.xml 文件加载库。

然而,还有另一个可能的来源,那就是 WAS JDK。如果该库位于 WAS JDK 中,那么它将始终从那里加载。在这些情况下,您必须从 pom.xml 文件中删除依赖项或将范围设置为“provided”。将范围设置为“provided”将在本地编译应用程序时使用依赖项,但在部署到 WAS 时则不会。

最后,还有一个用于 WAS 的类加载器和一个用于 JDK 的类加载器。如果两者都包含相同的类,例如 javax.server.ServletContext,那么它们仍然会出现异常 - 即使该类在ear文件中不存在。

在我们的特定情况下,我们必须像这样设置WAS:类加载器使用parent_last,托管模块使用parent_first。

Here is what is going on:

The same libraries are defined in both the pom.xml file for the applications AND the server.xml file on WAS. So, after WAS loads the class from the war file created from the pom.xml file for the application, it then attempts to load the same class from the library in shared libraries on WAS that is specified in the server.xml file.

The server.xml file will defined for the application in a folder defined by a path like this if your application was named corrservo65-01:

/usr/WebSphere905/AppServer/profiles/node01/config/cells/dwauslwasapp06Cell01/nodes/dwauslwasapp06Node01/servers/corrservo65-01

You can see which libraries are also being loaded from shared libraries by searching for the classloaders element in the server.xml file. Inside of the classloaders element there are libraries elements. Each one defines a library that is ALSO being loaded from the shared libraries on WAS as well as the library defined in the pom.xml file of the application.

For example, wsdl4j-1.6.2 is defined as a dependency in the pom.xml file:

 <dependency>
    <groupId>wsdl4j</groupId>
    <artifactId>wsdl4j</artifactId>
    <version>1.6.2</version>
</dependency>

Here is the same library being loaded from the shared libraries by WAS:

<classloaders xmi:id="Classloader_1629835928681" mode="PARENT_LAST">
   <libraries xmi:id="LibraryRef_1629835942246" libraryName="wsdl4j-1.6.2"/>
</classloaders>

When you set an application to parent_last in WAS then you have to also remove the references to libraries found in shared libraries from it as well. You then need to include those libraries in the pom.xml file of the application. This will cause ONLY the libraries to be loaded based on the pom.xml file.

However, there is another possible source and that is the WAS JDK. If the library is in the WAS JDK, then it will always load from there. In those cases, you must either remove the dependency from the pom.xml file or set the scope to "provided". Setting the scope to "provided" will use the dependency when the application is compiled locally, but not when it is deployed to WAS.

Lastly, there is a class loader for WAS and one for the JDK. If both contain the same class, say javax.server.ServletContext, then they will still the exception - even if the class does not exist in the ear file.

In our particular case, we had to set up WAS like this: Class loaders to use parent_last and Managed Modules to use parent_first.

分開簡單 2024-09-08 16:46:32

禁用字节码验证

java.lang.VerifyError - 运行时未经检查的异常
一旦类文件被加载到Websphere JVM中,下一步就是字节码验证。在字节码验证期间,如果我们的类违反了JVM约束,就会出现此错误。

禁用字节码验证。转到

管理控制台->server1->java和进程管理->进程定义->JVM参数`

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

 -Xverify:none 

,然后在工作区中打开 ApplicationDeploymentDescriptor xml 文件,转到部署选项卡,为 war 以及第一个选项选择 PARENT_LAST。这会阻止 xml 验证错误。

Disable the Bytecode Verification

java.lang.VerifyError - Runtime Unchecked Exception
once class file is loaded in Websphere JVM, then byte code varification is the next process.during byte code verification if our class in violating the JVM constraints ,then this error appears.

disable bytecode verification. Go to

admin console->server1->java and process management->process definition->JVM arguments`

And in JVM arguments pass the following string

 -Xverify:none 

and in workspace open the ApplicationDeploymentDescriptor xml file, go to deployment tab, select PARENT_LAST for war, as well as for first option. this stops the xml validations errors.

撩发小公举 2024-09-08 16:46:32

如果我们改为“父类加载器
首先”我们没有看到异常。
这与预期相反
行为。

是的,这是正确的,这是您看到这种行为的唯一方式。我建议你看看“你真的有类加载器吗?”谈谈,因为你的问题没有单一或简短的答案。

http://www.slideshare.net/guestd56374/do-你真的得到了类加载器
http://www.parleys.com/#sl=2& st=5&id=1585

If we change to "parent class loader
first" we do not see the exception.
This goes counter to the expected
behavior.

Yes, that's correct, it's the only way you can see such behaviour. I can suggest you yo take a look at the "Do you really get class loaders?" talk, as there is no single or short answer to your question.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文