你应该在客户端jar中提供依赖库吗?

时间:2009-11-17 03:08:23

标签: java client-library

我们为其他内部应用提供了一个客户端jar,以连接到我们应用的REST API。我们的API依赖于一些标准的Jakarta库。将这些JAR文件包含在我们的客户端jar文件中是最佳做法吗?或者你只记录依赖关系,并由客户确保他们在类路径上有这些jar?

5 个答案:

答案 0 :(得分:13)

你应该将任何第三方罐子作为超级罐子捆绑到你自己的罐子里,但最好包括你的分配中所需的所有罐子的副本。 lib目录或者什么。

主要原因是您的客户可能正在使用某种形式的依赖管理系统(maven / ivy等),并且提供实际上不属于您的项目的包和类将使这些方案无效。

有一种替代方法,即使用maven shade plugin之类的东西将依赖项重新定位到您自己的包名称空间中。这当然有一个缺点,你将增加你的库的代码大小,但从好的方面,你可以几乎保证你的依赖项的版本,而不影响你的客户可能使用的任何其他库。

编辑:回应Marcus Leon的评论:

捆绑/重新定位的可能解决方案:

  • 文档,请确保记录您的依赖项以及与以前版本的任何已知冲突 - 没有人实际读取它
  • 通过依赖管理系统分发您的库...就像maven或ivy repo一样,这些允许您在一组非常具体的边界(包括上层)中记录您的依赖项 - 仍然可以覆盖您的客户端知道他们正在这样做
  • 在MANIFEST.MF中添加OSGi信息 - 仅在客户实际使用OSGi时有用
  • 如果您的依赖项是使用maven构建的,或者在那些清单文件中有版本信息,那么您可以编写某种检查例程来扫描类路径并检查这些版本 - 有点极端

最后,实际上确保你拥有你想要的依赖是非常困难的,因为java是一种后期绑定语言,你可以在你的类路径上覆盖你的依赖项(即使是捆绑的)被某些人覆盖,包括一个不同的版本。

注意:我最近花了一个非常糟糕的一天试图找出我们的某个应用程序未能找到新版本的log4j的原因。原因:有人试图将其捆绑成一个随机完全无关的罐子。

答案 1 :(得分:5)

您应该包括您依赖的任何罐子。如果您允许客户端提供标准jar,您可以依赖它们来提供正确的版本。如果您包含您知道应用程序使用的版本,那么对您而言,这将更加轻松。

答案 2 :(得分:4)

捆绑到一个罐子里的优点很明显:

  • 客户的简单性

捆绑的缺点是:

  • 无法更新依赖库的版本
  • 隐藏必要的库实际上可能导致客户端与这些额外库的潜在冲突
  • 构建过程中的复杂性(但在Ant / Maven中很容易实现这一点)
  • 一些带有清单的图书馆不能不被疏忽和重新调整 - 您需要实际合并清单信息。虽然有Ant和Maven的支持。

另一种选择是使用单个主jar(您的代码),并将class-path manifest属性设置为吸入其他jar。我个人不喜欢这个,因为很容易错过这些半隐藏的依赖。

最后,如果你只说一两个罐子,我会把它们分开。如果您正在谈论10或15,您可能需要考虑捆绑。

答案 3 :(得分:2)

如果您将应用程序部署为独立应用程序,则应包括这些jar。如果您要为某人构建源代码并提供maven pom文件,那么您不一定需要。

答案 4 :(得分:0)

你对非常具体的库版本依赖关系表达了​​紧张(我可以理解,考虑到Hibernate在不同模块之间的紧密耦合 - 只有某些版本的Hibernate-annotations与一个hibernate-core一起使用,反过来必须与特定的休眠验证器一起使用。)

如果你知道一个包需要作为一个更大平台的一部分工作(比如,作为一个可能加载自己的jar的框架的插件),你真的需要更强大的多版本类OSGI加载(又名JSR-291): OSGI Technology

使用支持OSGI的框架(如Spring,Eclipse,Jonas或Glassfish),您可以在XML文件中指定特定的版本依赖项,如果依赖于bundle libfoo-1.1.4,则另一个插件依赖于libfoo-2.0a,OSGI依赖管理器将确保每个加载正确的版本。