【发布时间】:2012-07-25 12:40:25
【问题描述】:
在我的办公室里,仅仅提到 Xerces 这个词就足以激起开发者的杀气。粗略浏览一下关于 SO 的其他 Xerces 问题似乎表明几乎所有 Maven 用户在某个时候都被这个问题“触动”了。不幸的是,理解这个问题需要对 Xerces 的历史有一点了解......
历史
-
Xerces 是 Java 生态系统中使用最广泛的 XML 解析器。几乎每个用 Java 编写的库或框架都在一定程度上使用了 Xerces(如果不是直接传递,也可以传递)。
-
official binaries 中包含的 Xerces jar 直到今天还没有版本控制。例如,Xerces 2.11.0 实现 jar 被命名为
xercesImpl.jar而不是xercesImpl-2.11.0.jar。 -
Xerces 团队 does not use Maven,这意味着他们没有 将正式版本上传至Maven Central。
-
Xerces 曾经是 released as a single jar (
xerces.jar),但被拆分为两个 jar,一个包含 API (xml-apis.jar),另一个包含这些 API 的实现 (xercesImpl.jar)。许多旧的 Maven POM 仍然声明对xerces.jar的依赖。在过去的某个时候,Xerces 也以xmlParserAPIs.jar发布,一些较旧的 POM 也依赖它。 -
那些将 jar 部署到 Maven 存储库的人分配给 xml-apis 和 xercesImpl jar 的版本通常是不同的。例如,xml-apis 可能被赋予 1.3.03 版本,而 xercesImpl 可能被赋予 2.8.0 版本,即使两者都来自 Xerces 2.8.0。这是因为人们经常用它实现的规范版本来标记 xml-apis jar。这个here 有一个很好但不完整的细分。
-
更复杂的是,Xerces 是用于 Java API for XML Processing (JAXP) 的参考实现的 XML 解析器,包含在 JRE 中。实现类在
com.sun.*命名空间下重新打包,这使得直接访问它们很危险,因为它们在某些 JRE 中可能不可用。但是,并非所有 Xerces 功能都通过java.*和javax.*API 公开;例如,没有公开 Xerces 序列化的 API。 -
更令人困惑的是,几乎所有 servlet 容器(JBoss、Jetty、Glassfish、Tomcat 等)都在其一个或多个
/lib文件夹中随附 Xerces。
问题
冲突解决
出于上述某些(或全部)原因,许多 组织在他们的 POM。如果您有一个小型应用程序并且只使用 Maven Central,这并不是一个真正的问题,但它很快就会成为 Artifactory 或 Nexus 代理多个存储库(JBoss、Hibernate 等)的企业软件的问题:
例如,组织 A 可能将xml-apis 发布为:
<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>
同时,组织 B 可能会发布相同的jar:
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>
虽然B的jar比A的jar的版本低,但是Maven不知道
他们是同一个神器,因为他们有不同的
groupIds。因此,它不能执行冲突解决和两者
jars 将作为已解析的依赖项包含在内:
类加载器地狱
如上所述,JRE 在 JAXP RI 中随 Xerces 一起提供。虽然将所有 Xerces Maven 依赖项标记为 <exclusion>s 或 <provided> 会很好,但您所依赖的第三方代码可能会也可能不会与您正在使用的 JDK 的 JAXP 中提供的版本一起使用。此外,您可以在 servlet 容器中提供 Xerces jar 以应对。这给您留下了许多选择:您是否删除了 servlet 版本并希望您的容器在 JAXP 版本上运行?离开 servlet 版本是否更好,并希望您的应用程序框架在 servlet 版本上运行?如果上面列出的一两个未解决的冲突设法溜进您的产品(在大型组织中很容易发生),您很快就会发现自己陷入了类加载器的地狱,想知道类加载器在运行时选择了哪个版本的 Xerces 以及它是否将在 Windows 和 Linux 中选择相同的 jar(可能不会)。
解决方案?
我们已尝试将所有 Xerces Maven 依赖项标记为 <provided> 或 <exclusion>,但鉴于工件具有如此多的别名(xml-apis、@ 987654354@、xercesImpl、xmlParserAPIs 等)。此外,我们的第三方库/框架可能无法在 JAXP 版本或 servlet 容器提供的版本上运行。
我们如何用 Maven 最好地解决这个问题?我们是否必须对依赖项进行如此细粒度的控制,然后依赖分层类加载?是否有某种方法可以全局排除所有 Xerces 依赖项,并强制我们所有的框架/库使用 JAXP 版本?
更新:Joshua Spiewak 已将 Xerces 构建脚本的修补版本上传到 XERCESJ-1454,允许上传到 Maven Central。投票/观看/贡献这个问题,让我们一劳永逸地解决这个问题。
【问题讨论】:
-
感谢这个详细的问题。我不明白 xerces 团队的动机。我想他们会为那里的产品感到自豪并乐于使用它,但当前的 xerces 和 maven 状态是可耻的。即便如此,即使对我来说毫无意义,他们也可以做他们想做的事。我想知道 sonatype 的家伙是否有任何建议。
-
这可能是题外话,但这可能是我见过的更好的帖子。与问题更相关的是,您所描述的是我们可以遇到的最痛苦的问题之一。伟大的倡议!
-
@TravisSchneeberger 大部分复杂性是因为 Sun 选择在 JRE 本身中使用 Xerces。你很难为此责怪 Xerces 人。
-
通常我们尝试通过反复试验找到满足所有依赖库的 Xerces 版本,如果不可能,则重构为 WAR 以将应用程序拆分为单独的 WAR(单独的类加载器)。这个工具(我写的)通过允许查询 jars 和类的类路径来帮助理解 jhades.org 发生的事情 - 它也适用于服务器尚未启动的情况
-
如果您在 windows 中从 git bash 启动 servicemix 时遇到此错误,请快速评论:改为从“正常”cmd 启动它。
标签: java maven classloader dependency-management xerces