运行时使用插件的不同库版本

时间:2018-03-12 14:09:15

标签: java dependencies classloader conflict

在使用插件(例如Minecraft服务器,IDE等)的java应用程序中,很多时候需要使用一些库并将其隐藏在.jar中。

另一个插件也使用该库并且还包含在其中的.jar但不同版本时,问题就出现了,两个插件都能正常工作直到它们相遇然后,在同一个类加载器下,类加载器将只加载一个版本的库,另一个插件将使用与其设计版本不同的版本运行,如果库是库,则导致NoSuchMethodExceptions和/或不同的运行时行为不向后兼容。

注意:当2个依赖项具有相同的暂时依赖性但在不同版本中时,此问题关于如何使用maven进行编译。在这种情况下问题是不同的,因为你不能解决甚至在编译时检测依赖问题,因为不同版本的库不会在同一个.jar中,也不在同一个项目中,只在同一个类加载器下在给定的时间由2个插件可能由不同的作者用不同的目的。

避免此类冲突的一般策略是什么?

如果我正在创建自己的库而且它不能向后兼容,我该怎么做才能避免这个问题?

4 个答案:

答案 0 :(得分:0)

这是一个典型的java问题,并且正在进行一些重大的Java技术重新设计以改变它,尽管这些都是暂时的(Java 9或Java 10)。

目前,您可以做的最好的事情是对项目进行明确和定期的依赖性分析。

首先,请运行:mvn dependency:tree

您将能够看到同一依赖项的多个版本。不幸的是,在使用外部库时,您可能需要遵循它们使用的相同依赖版本,或者查找外部依赖项的更新版本。

我在依赖性分析中花了很多时间,而且大部分时间都是手动完成的(使用java的bug之一......)

如果您制作自己的软件,我们显式API版本化,并在您进行重大更改时对版本进行重大更改。

例如,使用“版本1.1”,“版本1.2”等。让人们知道版本1.1.11.1.4向后兼容1.1,但只要您引入API更改(发生这种情况),请转到版本1.2并迫使人们更新。

答案 1 :(得分:0)

不幸的是,这是我的应用程序中遇到的问题,尤其是当您无法管理或维护任何第三方外部系统时。要最小化这种情况,您应该创建父poms并将外部依赖项放在那里。还要定期检查是否存在任何不匹配或冲突,以及是否可以在开发阶段删除。当您的应用程序需要特定的依赖项时,有时会达到死锁状态,但架构的其余部分构建在不同的架构上。使用自定义构建包和大量更改推出新更改,有时您无法提供帮助。在这种情况下,预防措施胜于治疗。

答案 2 :(得分:0)

@ vikingsteve的回答解释了如何设计API以避免问题。不幸的是,有时候实际的考虑会妨碍你。例如,当您的代码依赖于两个大型库时(反过来)依赖于第三个库的不同版本。这些版本是不兼容的。

如果您处于这种情况,并且无法通过重写库来解决问题,请求库开发人员/供应商修复它等等,还有几个选择:

  • 您可以对软件进行重组,使具有冲突依赖关系的库位于不同的应用程序中;例如将它们分成“客户端”和“服务器”,或通过消息总线进行通信的“对等”,或通过管道进行通信的父和子进程。

  • 您可以重新构建代码库,以便将两个库加载到主类加载器的两个单独的子类加载器中。这将允许两个子类加载器加载两个版本的公共依赖项....并在JVM中共存。

显然,这些方法都不是一个神奇的子弹。两者都需要对您的应用程序进行一些修改。但他们可以解决你的“依赖地狱”问题。

答案 3 :(得分:0)

我的解决方案是使用所需的外部依赖关系创建另一个独立运行的jar应用程序,并在那里执行任务。