当前位置:  开发笔记 > 编程语言 > 正文

如何处理Java中的LinkageErrors?

如何解决《如何处理Java中的LinkageErrors?》经验,为你挑选了4个好方法。

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

我的应用程序使用Java插件框架,似乎无法将dom4j创建的XML文档转换为Batik的 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 ) 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> Alex Miller..:

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

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

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

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

委托(JDK中的默认值 - 询问父级,然后是我)

post-delegation(常见于插件,servlet和你想要隔离的地方 - 问我,然后是父母)

兄弟(在OSGi,Eclipse等依赖模型中很常见)

我不知道JPF类加载器使用什么委派策略,但关键是你想要加载一个版本的dom库,并且每个人都要从同一个位置获取该类.这可能意味着将其从类路径中删除并作为插件加载,或阻止Batik加载它或其他东西.



2> matt b..:

听起来像是一个类加载器层次结构问题.我不知道你的应用程序部署在什么类型的环境中,但有时这个问题可能发生在Web环境中 - 应用程序服务器创建类加载器的层次结构,类似于:

javahome/lib - 作为root
appserver/lib - 作为root
webapp/WEB-INF/lib的子代 - 作为root
等子代的子代

通常类加载器将加载委托给它们的父类加载器(这被称为" parent-first"),如果该类加载器找不到该类,则子类加载器会尝试.例如,如果在webapp/WEB-INF/lib中部署为JAR的类尝试加载一个类,首先它会要求appserver/lib对应的类加载器加载该类(这反过来要求对应于javahome/lib的类加载器)加载类),如果此查找失败,则搜索WEB-INF/lib以查找此类的匹配项.

在Web环境中,您可能会遇到此层次结构的问题.例如,我之前遇到的一个错误/问题是WEB-INF/lib中的一个类依赖于appserver/lib中部署的类,而后者依赖于部署在WEB-INF/lib中的类.这导致失败,因为虽然类加载器能够委托给父类加载器,但它们不能委托回树.因此,WEB-INF/lib类加载器会向appserver/lib类加载器请求类,appserver/lib类加载器会加载该类并尝试加载依赖类,并且失败,因为它无法在appserver/lib或javahome中找到该类/ lib目录下.

因此,虽然您可能没有在Web/app服务器环境中部署应用程序,但如果您的环境具有设置的类加载器层次结构,那么我太长的解释可能适用于您.可以?JPF是否能够实现某种类的加载器魔法来实现它的插件功能?



3> vineetv28219..:

可能这会对某人有所帮助,因为它对我来说非常好.可以通过集成自己的依赖项来解决该问题.按照这个简单的步骤

首先检查错误,应该是这样的:

方法执行失败:

java.lang.LinkageError:加载器约束违规:

解决方法时"org.slf4j.impl.StaticLoggerBinder .getLoggerFactory()Lorg/SLF4J/ILoggerFactory;"

当前类的类加载器(org/openmrs/module/ModuleClassLoader的实例)org/slf4j/LoggerFactory,

和已解析的类org/slf4j/impl/StaticLoggerBinder的类加载器(org/apache/catalina/loader/WebappClassLoader的实例),

为taticLoggerBinder.getLoggerFactory()类型提供不同的Class对象Lorg/slf4j/ILoggerFactory; 用于签名


    查看两个突出显示的类.谷歌搜索它们像"StaticLoggerBinder.class jar下载"和"LoggeraFactory.class jar下载".这将首先或在某些情况下,第二个链接(网站为您展示http://www.java2s.com),这是已包含在项目中的jar的版本之一.你可以自己聪明地识别它,但我们沉迷于谷歌;)

    之后你会知道jar文件名,在我的例子中它就像slf4j-log4j12-1.5.6.jar&slf4j-api-1.5.8

    现在这个文件的最新版本可以在这里找到http://mvnrepository.com/(实际上所有版本都是迄今为止,这是maven获取依赖关系的网站).

    现在将这两个文件添加为具有最新版本的依赖项(或保持两个文件版本相同,或者选择的版本都是旧的).以下是您必须包含在pom.xml中的依赖项



    org.slf4j
    slf4j-api
    1.7.7


    org.slf4j
    slf4j-log4j12
    1.7.7


如何从Maven站点获取dependecy定义



4> Adam Crume..:

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

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

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

推荐阅读
N个小灰流_701
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有