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系统上
你们当中有人遇到过这样的问题吗?有没有人知道如何解决这个问题,或者至少找到问题的核心
# 1 楼答案
亚历克斯和马特的回答很有帮助。我也可以从他们的分析中受益
在Netbeans RCP框架中使用Batik库时,我也遇到了同样的问题,Batik库被作为“库包装器模块”包含。如果其他一些模块使用XMLAPI,并且不需要为该模块建立对Batik的依赖,则会出现类装入器约束冲突问题,并显示类似的错误消息
在Netbeans中,单个模块使用专用的类装入器,模块之间的依赖关系意味着合适的类装入器委派路由
我可以通过从Batik库包中省略xml API jar文件来解决这个问题
# 2 楼答案
LinkageError是一个典型的例子,在这个例子中,一个C类由多个类加载器加载,这些类在同一代码中一起使用(比较、转换等)。不管它是相同的类名还是从相同的jar加载的,如果从另一个类加载器加载,那么来自一个类加载器的类总是被视为不同的类
这条信息(多年来有了很大改善)说:
因此,这里的问题在于解决SVGOM文档。createAttribute()方法,该方法使用org。w3c。多姆。Attr(标准DOM库的一部分)。但是,使用Batik加载的Attr版本是从不同的类加载器加载的,而不是从传递给该方法的Attr实例加载的
你会看到Batik的版本似乎是从Java插件加载的。您的是从“”加载的,它很可能是内置的JVM加载程序之一(引导类路径、ESOM或类路径)
三种主要的类加载器型号是:
我不知道JPF类加载器使用什么委托策略,但关键是您希望加载一个版本的dom库,并且每个人都从同一个位置获取该类。这可能意味着将其从类路径中删除并作为插件加载,或者阻止Batik加载它,或者其他一些事情
# 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 楼答案
也许这会对某人有所帮助,因为这对我来说很好。这个问题可以通过集成您自己的依赖项来解决。遵循以下简单步骤
首先检查如下错误:
请参见突出显示的两个类。谷歌搜索它们,比如“StaticLoggerBinder.class jar下载”&;“LoggeraFactory.class jar下载”。这将向您显示第一个链接,或者在某些情况下显示第二个链接(站点是http://www.java2s.com),这是您在项目中包含的jar版本之一。你可以自己聪明地识别它,但我们对谷歌上瘾了;)
之后,您将知道jar文件名,在我的例子中,它类似于slf4j-log4j12-1.5.6。jar&;slf4j-api-1.5.8
# 5 楼答案
你能指定一个类加载器吗?如果不是,请尝试指定上下文类加载器,如下所示:
我不熟悉Java插件框架,但我为Eclipse编写代码,并且时常遇到类似的问题。我不能保证它能修好,但可能值得一试
# 6 楼答案
如this question中所述,启用
-verbose:class
将使JVM记录有关正在加载的所有类的信息,这对于理解更复杂场景中的类来自何处非常有帮助;申请您得到的输出大致如下(从该问题复制):