在Java / Maven中处理“Xerces hell”?

本文翻译自:Dealing with “Xerces hell” in Java/Maven?

In my office, the mere mention of the word Xerces is enough to incite murderous rage from developers. 在我的办公室里,仅仅提到Xerces这个词就足以煽动开发者的凶悍愤怒。 A cursory glance at the other Xerces questions on SO seem to indicate that almost all Maven users are "touched" by this problem at some point. 粗略地看一眼其他Xerces关于SO的问题似乎表明,几乎所有Maven用户都会在某个时候“触及”这个问题。 Unfortunately, understanding the problem requires a bit of knowledge about the history of Xerces... 不幸的是,理解这个问题需要对Xerces的历史有一点了解......

History 历史

  • Xerces is the most widely used XML parser in the Java ecosystem. Xerces是Java生态系统中使用最广泛的XML解析器。 Almost every library or framework written in Java uses Xerces in some capacity (transitively, if not directly). 几乎每个用Java编写的库或框架都以某种身份使用Xerces(传递,如果不是直接的话)。

  • The Xerces jars included in the official binaries are, to this day, not versioned. 包含在官方二进制文件中的Xerces罐子直到今天还没有版本化。 For example, the Xerces 2.11.0 implementation jar is named xercesImpl.jar and not xercesImpl-2.11.0.jar . 例如,Xerces 2.11.0实现jar被命名为xercesImpl.jar而不是xercesImpl-2.11.0.jar

  • The Xerces team does not use Maven , which means they do not upload an official release to Maven Central . Xerces团队不使用Maven ,这意味着他们不会将正式版本上传到Maven Central

  • Xerces used to be released as a single jar ( xerces.jar ), but was split into two jars, one containing the API ( xml-apis.jar ) and one containing the implementations of those APIs ( xercesImpl.jar ). Xerces曾经作为单个jarxerces.jar )发布,但被分成两个jar,一个包含API( xml-apis.jar ),另一个包含这些API的实现( xercesImpl.jar )。 Many older Maven POMs still declare a dependency on xerces.jar . 许多较旧的Maven POM仍声明对xerces.jar的依赖。 At some point in the past, Xerces was also released as xmlParserAPIs.jar , which some older POMs also depend on. 在过去的某个时刻,Xerces也被发布为xmlParserAPIs.jar ,一些较旧的POM也依赖于它。

  • The versions assigned to the xml-apis and xercesImpl jars by those who deploy their jars to Maven repositories are often different. 分配给xml-apis和xercesImpl的版本由那些将其jar部署到Maven存储库的人通常是不同的。 For example, xml-apis might be given version 1.3.03 and xercesImpl might be given version 2.8.0, even though both are from Xerces 2.8.0. 例如,xml-apis可能是1.3.03版本,而xercesImpl可能是2.8.0版本,即使两者都来自Xerces 2.8.0。 This is because people often tag the xml-apis jar with the version of the specifications that it implements. 这是因为人们经常使用它实现的规范版本来标记xml-apis jar。 There is a very nice, but incomplete breakdown of this here . 还有就是这是一个非常不错的,但不完全击穿这里

  • To complicate matters, Xerces is the XML parser used in the reference implementation of the Java API for XML Processing (JAXP), included in the JRE. 更复杂的是,Xerces是包含在JRE中的Java API for XML Processing(JAXP)的参考实现中使用的XML解析器。 The implementation classes are repackaged under the com.sun.* namespace, which makes it dangerous to access them directly, as they may not be available in some JREs. 实现类在com.sun.*命名空间下重新打包,这使得直接访问它们很危险,因为它们可能在某些JRE中不可用。 However, not all of the Xerces functionality is exposed via the java.* and javax.* APIs; 但是,并非所有Xerces功能都通过java.*javax.* API公开; for example, there is no API that exposes Xerces serialization. 例如,没有API公开Xerces序列化。

  • Adding to the confusing mess, almost all servlet containers (JBoss, Jetty, Glassfish, Tomcat, etc.), ship with Xerces in one or more of their /lib folders. 添加到令人困惑的混乱中,几乎所有servlet容器(JBoss,Jetty,Glassfish,Tomcat等)都在一个或多个/lib文件夹中附带Xerces。

Problems 问题

Conflict Resolution 解决冲突

For some -- or perhaps all -- of the reasons above, many organizations publish and consume custom builds of Xerces in their POMs. 对于上述某些原因(或许是全部原因),许多组织在其POM中发布和使用Xerces的自定义构建。 This is not really a problem if you have a small application and are only using Maven Central, but it quickly becomes an issue for enterprise software where Artifactory or Nexus is proxying multiple repositories (JBoss, Hibernate, etc.): 如果你有一个小应用程序并且只使用Maven Central,这不是一个真正的问题,但它很快成为企业软件的问题,其中Artifactory或Nexus代理多个存储库(JBoss,Hibernate等):

由Artifactory代理的xml-apis

For example, organization A might publish xml-apis as: 例如,组织A可能会将xml-apis发布为:

<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>

Meanwhile, organization B might publish the same jar as: 同时,组织B可能会发布相同的jar

<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>

Although B's jar is a lower version than A's jar , Maven does not know that they are the same artifact because they have different groupId s. 虽然B的jar是比A的jar更低的版本,但Maven并不知道它们是相同的工件,因为它们有不同的groupId Thus, it cannot perform conflict resolution and both jar s will be included as resolved dependencies: 因此,它无法执行冲突解决,并且两个jar都将作为已解析的依赖项包含在内:

使用多个xml-apis解决了依赖关系

Classloader Hell Classloader Hell

As mentioned above, the JRE ships with Xerces in the JAXP RI. 如上所述,JRE在JAXP RI中附带Xerces。 While it would be nice to mark all Xerces Maven dependencies as <exclusion> s or as <provided> , the third-party code you depend on may or may not work with the version provided in JAXP of the JDK you're using. 虽然将所有Xerces Maven依赖项标记为<exclusion><provided>会很好,但您所依赖的第三方代码可能会也可能不会与您正在使用的JDK的JAXP中提供的版本一起使用。 In addition, you have the Xerces jars shipped in your servlet container to contend with. 此外,您还可以在servlet容器中附带Xerces jar以进行竞争。 This leaves you with a number of choices: Do you delete the servlet version and hope that your container runs on the JAXP version? 这给您留下了许多选择:您是否删除了servlet版本并希望您的容器在JAXP版本上运行? Is it better to leave the servlet version, and hope that your application frameworks run on the servlet version? 离开servlet版本是否更好,并希望您的应用程序框架在servlet版本上运行? If one or two of the unresolved conflicts outlined above manage to slip into your product (easy to happen in a large organization), you quickly find yourself in classloader hell, wondering which version of Xerces the classloader is picking at runtime and whether or not it will pick the same jar in Windows and Linux (probably not). 如果上面列出的一个或两个未解决的冲突进入您的产品(很容易在大型组织中发生),您很快就会发现自己处于类加载器地狱,想知道类加载器在运行时选择的Xerces版本以及是否将在Windows和Linux中选择相同的jar(可能不是)。

Solutions? 解决方案?

We've tried marking all Xerces Maven dependencies as <provided> or as an <exclusion> , but this is difficult to enforce (especially with a large team) given that the artifacts have so many aliases ( xml-apis , xerces , xercesImpl , xmlParserAPIs , etc.). 我们已经尝试将所有Xerces Maven依赖项标记为<provided><exclusion> ,但这很难强制执行(特别是对于大型团队),因为工件有很多别名( xml-apisxercesxercesImplxmlParserAPIs等)。 Additionally, our third party libs/frameworks may not run on the JAXP version or the version provided by a servlet container. 此外,我们的第三方库/框架可能无法在JAXP版本或servlet容器提供的版本上运行。

How can we best address this problem with Maven? 我们怎样才能最好地解决Maven的这个问题? Do we have to exercise such fine-grained control over our dependencies, and then rely on tiered classloading? 我们是否必须对依赖关系进行如此细粒度的控制,然后依赖分层类加载? Is there some way to globally exclude all Xerces dependencies, and force all of our frameworks/libs to use the JAXP version? 有没有办法全局排除所有Xerces依赖项,并强制我们所有的框架/库使用JAXP版本?


UPDATE : Joshua Spiewak has uploaded a patched version of the Xerces build scripts to XERCESJ-1454 that allows for upload to Maven Central. 更新 :Joshua Spiewak已将Xerces构建脚本的修补版本上传到XERCESJ-1454 ,允许上传到Maven Central。 Vote/watch/contribute to this issue and let's fix this problem once and for all. 投票/观看/贡献这个问题,让我们一劳永逸地解决这个问题。


#1楼

参考:https://stackoom.com/question/mzrw/在Java-Maven中处理-Xerces-hell


#2楼

I guess there is one question you need to answer: 我想你需要回答一个问题:

Does there exist a xerces*.jar that everything in your application can live with? 是否存在xerces * .jar,应用程序中的所有内容都可以使用?

If not you are basically screwed and would have to use something like OSGI, which allows you to have different versions of a library loaded at the same time. 如果不是,你基本上搞砸了,并且必须使用像OSGI这样的东西,它允许你同时加载不同版本的库。 Be warned that it basically replaces jar version issues with classloader issues ... 请注意,它基本上用类加载器问题替换jar版本问题......

If there exists such a version you could make your repository return that version for all kinds of dependencies. 如果存在这样的版本,您可以使您的存储库为所有类型的依赖项返回该版本。 It's an ugly hack and would end up with the same xerces implementation in your classpath multiple times but better than having multiple different versions of xerces. 这是一个丑陋的黑客攻击,并且会在你的类路径中多次使用相同的xerces实现,但是比拥有多个不同版本的xerces更好。

You could exclude every dependency to xerces and add one to the version you want to use. 您可以将每个依赖项排除在xerces之外,并将一个依赖项添加到要使用的版本中。

I wonder if you can write some kind of version resolution strategy as a plugin for maven. 我想知道你是否可以编写某种版本解析策略作为maven的插件。 This would probably the nicest solution but if at all feasible needs some research and coding. 这可能是最好的解决方案,但如果可行则需要一些研究和编码。

For the version contained in your runtime environment, you'll have to make sure it either gets removed from the application classpath or the application jars get considered first for classloading before the lib folder of the server get considered. 对于运行时环境中包含的版本,您必须确保从应用程序类路径中删除它,或者在考虑服务器的lib文件夹之前首先考虑应用程序jar进行类加载。

So to wrap it up: It's a mess and that won't change. 所以把它包起来:这是一团糟,不会改变。


#3楼

坦率地说,我们遇到的几乎所有东西都适用于JAXP版本,所以我们总是排除 xml-apisxercesImpl


#4楼

You could use the maven enforcer plugin with the banned dependency rule. 您可以将maven enforcer插件与禁止的依赖关系规则一起使用。 This would allow you to ban all the aliases that you don't want and allow only the one you do want. 这将允许您禁止所有您不想要的别名,并且只允许您想要的那些别名。 These rules will fail the maven build of your project when violated. 违反时,这些规则将使项目的maven构建失败。 Furthermore, if this rule applies to all projects in an enterprise you could put the plugin configuration in a corporate parent pom. 此外,如果此规则适用于企业中的所有项目,则可以将插件配置放在公司父pom中。

see: 看到:


#5楼

There are 2.11.0 JARs (and source JARs!) of Xerces in Maven Central since 20th February 2013! 自2013年2月20日起,Maven Central的Xerces有2.11.0 JAR (和源JAR!) See Xerces in Maven Central . 参见Maven Central的Xerces I wonder why they haven't resolved https://issues.apache.org/jira/browse/XERCESJ-1454 ... 我想知道为什么他们没有解决https://issues.apache.org/jira/browse/XERCESJ-1454 ...

I've used: 我用过:

<dependency>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    <version>2.11.0</version>
</dependency>

and all dependencies have resolved fine - even proper xml-apis-1.4.01 ! 并且所有依赖关系都已经解决了 - 甚至是正确的xml-apis-1.4.01

And what's most important (and what wasn't obvious in the past) - the JAR in Maven Central is the same JAR as in the official Xerces-J-bin.2.11.0.zip distribution . 最重要的(以及过去不明显的) - Maven Central中的JAR与官方Xerces-J-bin.2.11.0.zip发行版中的JAR相同

I couldn't however find xml-schema-1.1-beta version - it can't be a Maven classifier -ed version because of additional dependencies. 然而,我无法找到xml-schema-1.1-beta版本 - 由于其他依赖性,它不能是Maven classifier -ed版本。


#6楼

What would help, except for excluding, is modular dependencies. 除了排除外,有用的是模块化依赖。

With one flat classloading (standalone app), or semi-hierarchical (JBoss AS/EAP 5.x) this was a problem. 使用一个平面类加载(独立应用程序)或半分层(JBoss AS / EAP 5.x)这是一个问题。

But with modular frameworks like OSGi and JBoss Modules , this is not so much pain anymore. 但是对于像OSGiJBoss Modules这样的模块化框架,这不再那么痛苦了。 The libraries may use whichever library they want, independently. 图书馆可以独立使用他们想要的任何图书馆。

Of course, it's still most recommendable to stick with just a single implementation and version, but if there's no other way (using extra features from more libs), then modularizing might save you. 当然,最好只推荐一个实现和版本,但如果没有其他办法(使用更多库中的额外功能),那么模块化可能会省去你。

A good example of JBoss Modules in action is, naturally, JBoss AS 7 / EAP 6 / WildFly 8 , for which it was primarily developed. JBoss模块运行的一个很好的例子当然是JBoss AS 7 / EAP 6 / WildFly 8 ,它主要是为它开发的。

Example module definition: 示例模块定义:

<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.jboss.msc">
    <main-class name="org.jboss.msc.Version"/>
    <properties>
        <property name="my.property" value="foo"/>
    </properties>
    <resources>
        <resource-root path="jboss-msc-1.0.1.GA.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api"/>
        <module name="org.jboss.logging"/>
        <module name="org.jboss.modules"/>
        <!-- Optional deps -->
        <module name="javax.inject.api" optional="true"/>
        <module name="org.jboss.threads" optional="true"/>
    </dependencies>
</module>

In comparison with OSGi, JBoss Modules is simpler and faster. 与OSGi相比,JBoss模块更简单,更快捷。 While missing certain features, it's sufficient for most projects which are (mostly) under control of one vendor, and allow stunning fast boot (due to paralelized dependencies resolving). 虽然缺少某些功能,但对于大多数(一般)在一个供应商的控制下的项目来说,它足够了,并允许惊人的快速启动(由于并行的依赖关系解决)。

Note that there's a modularization effort underway for Java 8 , but AFAIK that's primarily to modularize the JRE itself, not sure whether it will be applicable to apps. 请注意, Java 8正在进行模块化工作 ,但AFAIK主要用于模块化JRE本身,不确定它是否适用于应用程序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值