有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

linux如何处理Java中的LinkageErrors?

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

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

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

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系统上

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


共 (6) 个答案

  1. # 1 楼答案

    亚历克斯和马特的回答很有帮助。我也可以从他们的分析中受益

    在Netbeans RCP框架中使用Batik库时,我也遇到了同样的问题,Batik库被作为“库包装器模块”包含。如果其他一些模块使用XMLAPI,并且不需要为该模块建立对Batik的依赖,则会出现类装入器约束冲突问题,并显示类似的错误消息

    在Netbeans中,单个模块使用专用的类装入器,模块之间的依赖关系意味着合适的类装入器委派路由

    我可以通过从Batik库包中省略xml API jar文件来解决这个问题

  2. # 2 楼答案

    LinkageError是一个典型的例子,在这个例子中,一个C类由多个类加载器加载,这些类在同一代码中一起使用(比较、转换等)。不管它是相同的类名还是从相同的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
    

    因此,这里的问题在于解决SVGOM文档。createAttribute()方法,该方法使用org。w3c。多姆。Attr(标准DOM库的一部分)。但是,使用Batik加载的Attr版本是从不同的类加载器加载的,而不是从传递给该方法的Attr实例加载的

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

    三种主要的类加载器型号是:

    • 委派(JDK-ask父级中的默认值,然后是me)
    • 授权后(常见于插件、servlet和需要隔离的地方——问我,然后问家长)
    • 同级(在OSGi、Eclipse等依赖模型中很常见)

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

  3. # 3 楼答案

    听起来像是类加载器层次结构问题。我不知道您的应用程序部署在哪种类型的环境中,但有时这个问题会发生在web环境中——应用程序服务器会创建一个类加载器层次结构,类似于:

    javahome/lib-作为根目录
    appserver/lib-作为根的子级
    webapp/WEB-INF/lib-作为根的子级的子级

    通常,类加载器将加载委托给其父类加载器(这称为“parent-first”),如果该类加载器找不到该类,则子类加载器会尝试加载。例如,如果在webapp/WEB-INF/lib中部署为JAR的类试图加载一个类,那么它首先会请求appserver/lib对应的类加载器加载该类(这反过来又会请求javahome/lib对应的类加载器加载该类),如果该查找失败,则会搜索WEB-INF/lib以查找与该类的匹配项

    在web环境中,这种层次结构可能会出现问题。例如,我以前遇到的一个错误/问题是,WEB-INF/lib中的一个类依赖于部署在appserver/lib中的一个类,而appserver/lib又依赖于部署在WEB-INF/lib中的一个类。这导致了失败,因为类加载器能够委托给父类加载器,但不能向下委托树。因此,WEB-INF/lib类加载器会向appserver/lib类加载器请求一个类,appserver/lib类加载器会加载该类并尝试加载依赖类,但失败了,因为它在appserver/lib或javahome/lib中找不到该类

    因此,虽然您可能没有在web/app服务器环境中部署应用程序,但如果您的环境设置了类加载器的层次结构,那么我的解释可能太长。是吗?JPF是否在做一些类加载器的魔术,以便能够实现它的插件功能

  4. # 4 楼答案

    也许这会对某人有所帮助,因为这对我来说很好。这个问题可以通过集成您自己的依赖项来解决。遵循以下简单步骤

    首先检查如下错误:

    • 方法执行失败:
    • 爪哇。lang.LinkageError:加载程序约束冲突:
    • 解析方法“org.slf4j.impl.StaticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory;”
    • 当前类org/slf4j/LoggerFactory的类加载器(org/openmrs/module/ModuleClassLoader的实例)
    • 以及解析类的类加载器(org/apache/catalina/loader/WebappClassLoader的实例),org/slf4j/impl/StaticLoggerBinder
    • 具有不同类型的类对象。getLoggerFactory()Lorg/slf4j/ILoggerFactory;在签名中使用

    1. 请参见突出显示的两个类。谷歌搜索它们,比如“StaticLoggerBinder.class jar下载”&;“LoggeraFactory.class jar下载”。这将向您显示第一个链接,或者在某些情况下显示第二个链接(站点是http://www.java2s.com),这是您在项目中包含的jar版本之一。你可以自己聪明地识别它,但我们对谷歌上瘾了;)

    2. 之后,您将知道jar文件名,在我的例子中,它类似于slf4j-log4j12-1.5.6。jar&;slf4j-api-1.5.8

    3. 现在,这个文件的最新版本在这里http://mvnrepository.com/可用(实际上是到目前为止的所有版本,这是maven获取依赖项的站点)
    4. 现在将这两个文件添加为具有最新版本的依赖项(或者保持两个文件版本相同,或者选择的版本都是旧版本)。以下是pom中必须包含的依赖项。xml

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.7</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.7</version>
    </dependency>
    

    How to get dependecy definition from Maven Site

  5. # 5 楼答案

    你能指定一个类加载器吗?如果不是,请尝试指定上下文类加载器,如下所示:

    Thread thread = Thread.currentThread();
    ClassLoader contextClassLoader = thread.getContextClassLoader();
    try {
        thread.setContextClassLoader(yourClassLoader);
        callDom4j();
    } finally {
        thread.setContextClassLoader(contextClassLoader);
    }
    

    我不熟悉Java插件框架,但我为Eclipse编写代码,并且时常遇到类似的问题。我不能保证它能修好,但可能值得一试

  6. # 6 楼答案

    this question中所述,启用-verbose:class将使JVM记录有关正在加载的所有类的信息,这对于理解更复杂场景中的类来自何处非常有帮助;申请

    您得到的输出大致如下(从该问题复制):

    [Opened /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
    [Opened /usr/java/j2sdk1.4.1/jre/lib/sunrsasign.jar]
    [Opened /usr/java/j2sdk1.4.1/jre/lib/jsse.jar]
    [Opened /usr/java/j2sdk1.4.1/jre/lib/jce.jar]
    [Opened /usr/java/j2sdk1.4.1/jre/lib/charsets.jar]
    [Loaded java.lang.Object from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
    [Loaded java.io.Serializable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
    [Loaded java.lang.Comparable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
    [Loaded java.lang.CharSequence from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
    [Loaded java.lang.String from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]