在Java中访问包的多个版本

在Java中访问包的多个版本,java,osgi,apache-commons,classloader,Java,Osgi,Apache Commons,Classloader,我们有几个应用程序使用ApacheHttpClient 3发出HTTP请求。最近,我们还开始创建基于各种原因使用HTTPClient 4的web服务客户端。Apache的立场是“主要版本不向后兼容”。虽然我很想更新我们所有的项目以使用版本4,但这根本不可行 所以,虽然我的主要问题相当笼统,但我的特殊问题是如何在同一个应用程序中使用HTTPClient版本3和版本4?在本例中,应用程序可以是web、桌面或命令行应用程序 我读过这本书,它看起来很接近,但我不太在乎动态部分。事实上,我希望JAR与应用

我们有几个应用程序使用ApacheHttpClient 3发出HTTP请求。最近,我们还开始创建基于各种原因使用HTTPClient 4的web服务客户端。Apache的立场是“主要版本不向后兼容”。虽然我很想更新我们所有的项目以使用版本4,但这根本不可行

所以,虽然我的主要问题相当笼统,但我的特殊问题是如何在同一个应用程序中使用HTTPClient版本3和版本4?在本例中,应用程序可以是web、桌面或命令行应用程序

我读过这本书,它看起来很接近,但我不太在乎动态部分。事实上,我希望JAR与应用程序一起提供(例如,WEB应用程序的WEB-INF/lib),我也看到在类似的问题中提到了很多,但这似乎有些过火,或者可能过于复杂(也许一个简单的例子可以证明不是这样)


最后,我希望能够为团队提供一组JAR,他们可以将其放入其中,并且使用HTTP Client 3独立于他们的项目工作。

使用多个类加载器,每个类加载器用于您希望使用的HTTP客户端


最简单的方法是扩展URLClassLoader,并对其进行破解,分别对每个版本的类路径进行硬编码。然后,您只需要确保代码的其余部分知道要使用哪个版本的HTTP客户端(并访问正确的类加载器来访问它)。

您必须为v3和v4使用单独的类加载器。将v3和v4 JAR放在应用程序类路径之外的单独文件夹中。使用URLClassLoadedr加载每个版本。传递给每个类加载器的URL应该包含指向特定版本HTTP客户端的URL


但是我可以给你一个建议吗?在开始之前,首先检查您是否真的需要所有这些。这是正确的,版本可能不兼容。但是它们很有可能是这样的。

一个简单而直接的解决方案是获取HttpClient3和HttpClient4的源代码,并将包名重构为

org.apache.commons.httpclient3用于httpclient3,而org.apache.commons.httpclient4用于httpclient4以避免冲突。然后编译,打包,完成


现在很容易在这两个实现之间切换,并且它们在类加载器中不会发生冲突。

正如其他人所说的,您可以创建多个类加载器并单独加载这两个版本。这部分很简单

问题是,这实际上分割了您的“类空间”,并且仍然很难从应用程序的某些部分引用v3,而从应用程序的其他部分引用v4。您必须非常小心地对应用程序进行分区。。。那么,为什么不将其拆分并交付两个应用程序呢


如果您能够将功能考虑到服务中,OSGi可能是一个解决方案。但是,将遗留应用程序转换为OSGi并不是一件容易的事情,而且它肯定不会是从您所陷入的陷阱中廉价逃脱的方法。我是作为一本关于OSGi的书的作者和一位著名的OSGi福音传道者这样说的。将应用程序转换为OSGi的长期目标将给您带来巨大的好处,但同时也会带来巨大的前期成本。

我认为您的意思是“它们很有可能不是”我知道HTTP客户机v3和V4不能很好地结合在一起。在这种情况下,架构治理是一个好主意:要么坚持使用版本3,要么将所有内容都迁移到版本4。现在,您必须为一个拼凑解决方案支付实施成本,而且随着时间的推移,它只会变得更糟。@Anon:无意冒犯,但在不了解情况的情况下,我不会建议您做出这样一个笼统的声明。我说“出于各种原因”来避免这样的评论。OSGi至少是有效的(你需要决定它是否太过了),除了有两个web服务器之外,我不知道有什么简单的方法可以做到这一点,库的每个版本一个。对于必须随WARs一起提供JAR的web应用程序,这将如何工作?您提供引用的每个库的所有版本,但将它们放在web inf/lib之外的其他位置。您的自定义类加载器将在“其他地方”位置查找。这防止了war容器直接引用它们。虽然这对一个jar有效,但它产生的问题比解决的问题还要多。例如,您可能需要apache.commons.logging,这两个版本将依赖于不同版本的commons日志(因为它们在不同的时间发布)。现在,您可以按照上述方式重新打包commons日志记录,但随后必须返回并手动编辑重新打包的http客户端中的所有源代码,以便正确引用。很快,这样的解决方案就变得一团糟。他们真的依赖于不同版本的commons日志吗?最新的一个应该可以和这两个都很好地配合,不是吗?请注意,下议院的朗人正走这条路。Commons Lang 3将使用包名org.apache.Commons.lang3。如果你将要进行不兼容的API更改,那么一个新的包名可能不是最糟糕的主意。Edwin,我不认为仅仅凭猜测就可以说“这会产生比解决问题更多的问题”。我认为如果您使用最新版本的commons日志,不会有任何问题。我使用了许多依赖于不同jcl版本的apache项目,并且使用最新的jcl不会导致问题。但是,您可以使用slf4j及其jcl-over-slf4j.jar完全删除jcl,并在slf4j上桥接所有内容,以消除jcl版本冲突。没有必要使用jcl。如果产品使用最新版本,这不是问题。当处理依赖关系时,问题就出现了,即双包装项的“旧”版本与下游依赖关系的“新”版本不兼容。“这种情况经常发生吗?”这不是真正的问题,好像它发生了