开发一个高度基于XML的Java应用程序,最近我在Ubuntu Linux上遇到了一个有趣的问题。
我的应用程序使用Java Plugin Framework,似乎无法将dom4j创建的XML文档转换为SVG规范的Batik's实现。
在控制台上,我了解到发生了错误:
线程“ AWT-EventQueue-0”中的异常java.lang.LinkageError:接口可初始化中违反了加载程序约束:解决方法“ org.apache.batik.dom.svg.SVGOMDocument.createAttribute(Ljava / lang / String;)Lorg / w3c / dom / Attr;”当前类org / apache / batik / dom / svg / SVGOMDocument的类加载器(org / java / plugin / standard / StandardPluginClassLoader的实例)和接口org / w3c /的类加载器(的实例) dom / Document对于签名中使用的org / w3c / dom / Attr类型具有不同的Class对象在org.apache.batik.dom.svg.SVGDOMImplementation.createDocument(SVGDOMImplementation.java:149)在org.dom4j.io.DOMWriter.createDomDocument(DOMWriter.java:361)在org.dom4j.io.DOMWriter.write(DOMWriter.java:138)
我认为问题是由来自JVM的原始类加载器与插件框架部署的类加载器之间的冲突引起的。
据我所知,不可能为框架指定要使用的类加载器。可能有可能被黑客入侵,但是我宁愿使用一种不太积极的方法来解决此问题,因为(出于某种原因)它仅在Linux系统上发生。
你们中的一个人遇到过这样的问题,并且不知道如何解决这个问题,或者至少是问题的核心吗?
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或类路径)。
三个杰出的类加载器模型是:
我不知道JPF类加载器使用什么委派策略,但是关键是要加载dom库的一个版本,并且每个人都希望从同一位置获取该类。这可能意味着将其从类路径中删除并作为插件加载,或阻止Batik加载它,或进行其他操作。
听起来像类加载器层次结构问题。我无法确定您的应用程序部署在哪种环境中,但是有时在Web环境中可能会出现此问题-应用程序服务器在其中创建类加载器的层次结构,类似于:]
也许这会对某人有帮助,因为它对我非常有用。可以通过集成自己的依赖项来解决此问题。遵循以下简单步骤
您可以指定类加载器吗?如果没有,请尝试像这样指定上下文类加载器:
Alex和Matt的回答非常有帮助。我也可以从他们的分析中受益。
按照this question中的指定,启用-verbose:class
将使有关所有正在加载的类的JVM日志信息,这对于了解类在更复杂的场景和应用程序中的来源非常有用。
我发现该类被加载两次。查找原因是parallelWebappClassLoader首先自行加载类,而不是使用其父classLoader。