线程的上下文类装入器和普通类装入器之间的区别是什么?

也就是说,如果Thread.currentThread().getContextClassLoader()和getClass().getClassLoader()返回不同的类装入器对象,将使用哪一个?

为什么在Java中这么难做到这一点?如果您希望拥有任何类型的模块系统,您需要能够动态加载JAR文件。有人告诉我,有一种方法可以通过编写自己的ClassLoader来实现,但这需要做很多工作,因为(至少在我看来)应该像调用以JAR文件作为参数的方法一样简单。

对实现这一功能的简单代码有什么建议吗?

在我的办公室里,仅仅提到Xerces一词就足以激起开发商的愤怒。粗略地看一下Xerces关于SO的其他问题,似乎表明几乎所有Maven用户都在某个时刻被这个问题“触动”了。不幸的是,了解这个问题需要一些关于薛西斯历史的知识。。。

历史

Xerces是Java生态系统中使用最广泛的XML解析器。几乎每一个用Java编写的库或框架都在某种程度上使用Xerces(如果不是直接使用的话,也是过渡使用的)。到目前为止,官方二进制文件中包含的Xerces jar还没有版本。例如,Xerces 2.11.0实现jar名为xercesImpl.jar,而不是xercesImpl-2.11.0.jar。Xerces团队不使用Maven,这意味着他们不使用将官方版本上传到Maven Central。Xerces以前是作为一个单独的jar(Xerces.jar)发布的,但被分成两个jar,一个包含API(xmlapis.jar),另一个包含这些API的实现(xercesImpl.jar)。许多旧的Maven POM仍然声明对Xerces.jar的依赖。在过去的某个时候,Xerces也被发布为xmlParserAPIs.jar,一些旧的POM也依赖于此。将jar部署到Maven存储库的人员分配给xmlapi和xercesImpl jar的版本通常不同。例如,xml api的版本可能为1.3.03,xercesImpl的版本可能是2.8.0,尽管两者都来自Xerces 2.8.0。这是因为人们经常用它实现的规范版本来标记xmlapis jar。这里有一个非常好的,但不完整的分解。更复杂的是,Xerces是JRE中包含的Java API for XML Processing(JAXP)参考实现中使用的XML解析器。实现类在com.sun.*命名空间下重新打包,这使得直接访问它们很危险,因为它们在某些JRE中可能不可用。然而,并非所有Xerces功能都通过java.*和javax.*API公开;例如,没有公开Xerces序列化的API。更令人困惑的是,几乎所有的servlet容器(JBoss、Jetty、Glassfish、Tomcat等)都在一个或多个/lib文件夹中附带Xerces。

问题

冲突解决方案

出于上述原因组织在其聚甲醛。如果您有一个小型应用程序,并且只使用Maven Central,这并不是一个真正的问题,但对于Artifactry或Nexus代理多个存储库(JBoss、Hibernate等)的企业软件来说,这很快就会成为一个问题:

例如,组织A可以将xmlapi发布为:

<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不知道它们是同一个工件,因为它们有不同的组ID。因此,它无法执行冲突解决和两者jar将作为已解析的依赖项包含:

Classloader地狱

如上所述,JRE在JAXP RI中随Xerces一起提供。虽然最好将所有Xerces Maven依赖项标记为<exclusion>或<provided>,但您依赖的第三方代码可能与您使用的JDK的JAXP中提供的版本兼容,也可能不兼容。此外,servlet容器中还提供了Xerces jar以应对。这给您留下了许多选择:您是否删除servlet版本并希望容器在JAXP版本上运行?离开servlet版本,并希望您的应用程序框架在servlet版本上运行是不是更好?如果上面列出的一个或两个未解决的冲突成功地渗入到您的产品中(在大型组织中很容易发生),您很快就会发现自己处于类加载器的地狱中,想知道类加载器在运行时选择的是哪个版本的Xerces,以及它是否会在Windows和Linux中选择相同的jar(可能不会)。

解决?

我们已经尝试将所有Xerces Maven依赖项标记为<provided>或<exclusion>,但这很难实施(尤其是在大型团队中),因为工件有太多别名(xmlapi、Xerces、xercesImpl、xmlParserAPI等)。此外,我们的第三方libs/framework可能无法在JAXP版本或servlet容器提供的版本上运行。

我们如何用Maven最好地解决这个问题?我们是否必须对依赖项进行细粒度控制,然后依赖分层类加载?是否有某种方法可以全局排除所有Xerces依赖项,并强制所有框架/库使用JAXP版本?


更新:Joshua Spiewak已将Xerces构建脚本的补丁版本上传到XERCESJ-1454,允许上传到Maven Central。投票/观看/贡献这个问题,让我们一劳永逸地解决这个问题。