java - 如何处理Java中的链接错误?

标签 java linux classloader linkageerror

在开发一个高度基于 XML 的 Java 应用程序时,我最近在 Ubuntu Linux 上遇到了一个有趣的问题。

我的应用程序,使用 Java Plugin Framework ,似乎无法转换 dom4j -创建 XML 文档至 Batik's SVG 规范的实现。

在控制台上,我了解到发生了错误:

Exception in thread "AWT-EventQueue-0" java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "org.apache.batik.dom.svg.SVGOMDocument.createAttribute(Ljava/lang/String;)Lorg/w3c/dom/Attr;" the class loader (instance of org/java/plugin/standard/StandardPluginClassLoader) of the current class, org/apache/batik/dom/svg/SVGOMDocument, and the class loader (instance of <bootloader>) for interface org/w3c/dom/Document have different Class objects for the type org/w3c/dom/Attr used in the signature
    at org.apache.batik.dom.svg.SVGDOMImplementation.createDocument(SVGDOMImplementation.java:149)
    at org.dom4j.io.DOMWriter.createDomDocument(DOMWriter.java:361)
    at org.dom4j.io.DOMWriter.write(DOMWriter.java:138)

我认为该问题是由 JVM 的原始类加载器与插件框架部署的类加载器之间的冲突引起的。

据我所知,不可能指定框架使用的类加载器。也许可以破解它,但我更喜欢采用不太激进的方法来解决这个问题,因为(无论出于何种原因)它只发生在 Linux 系统上。

你们中有人遇到过这样的问题并且知道如何解决它或者至少找到问题的核心吗?

最佳答案

LinkageError 是一种经典情况,即您有一个由多个类加载器加载的类 C,并且这些类在同一代码中一起使用(比较、强制转换等),您将得到 LinkageError。如果它是相同的类名,或者即使它是从相同的 jar 加载的,也没关系 - 如果从另一个类加载器加载,来自一个类加载器的类始终被视为不同的类。

该消息(多年来已经有了很大改进)说:

Exception in thread "AWT-EventQueue-0" java.lang.LinkageError: 
loader constraint violation in interface itable initialization: 
when resolving method "org.apache.batik.dom.svg.SVGOMDocument.createAttribute(Ljava/lang/String;)Lorg/w3c/dom/Attr;" 
the class loader (instance of org/java/plugin/standard/StandardPluginClassLoader) 
of the current class, org/apache/batik/dom/svg/SVGOMDocument, 
and the class loader (instance of ) for interface org/w3c/dom/Document 
have different Class objects for the type org/w3c/dom/Attr used in the signature

所以,这里的问题在于解决 SVGOMDocument.createAttribute() 方法,该方法使用 org.w3c.dom.Attr (标准 DOM 库的一部分)。但是,使用 Batik 加载的 Attr 版本是从与传递给该方法的 Attr 实例不同的类加载器加载的。

您会看到 Batik 的版本似乎是从 Java 插件加载的。您的加载器是从“”加载的,它很可能是内置 JVM 加载器之一(引导类路径、ESOM 或类路径)。

三个著名的类加载器模型是:

  • 委托(delegate)(JDK 中的默认设置 - 先询问 parent ,然后询问我)
  • 委托(delegate)后(常见于插件、Servlet 以及您想要隔离的地方 - 先问我,然后问家长)
  • 同级(常见于 OSGi、Eclipse 等依赖模型中)

我不知道 JPF 类加载器使用什么委托(delegate)策略,但关键是您希望加载一个版本的 dom 库,并且每个人都从同一位置获取该类。这可能意味着将其从类路径中删除并作为插件加载,或者阻止 Batik 加载它,或者其他什么。

关于java - 如何处理Java中的链接错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57801556/

相关文章:

java - 线程 "main"java.lang.ClassCastException : [Ljava. lang.Object 中的异常;不能转换为 model.AdminPopulate

java ;文件输入输出中特定字符的换行

c - fork,Linux 中的 execlp

c++ - 如何用ICU编译sqlite?

java - 什么是 Java 中的应用程序级类?

java - 如何从另一个 jar 文件调用一个类?

java - 逆向工程图像裁剪和调整大小

linux - 使用 snmp 监控部署在 Tomcat 中的 J2EE 应用程序

java - URLClassLoader 找不到类

java - 为二进制搜索的复合对象编写比较器