17

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

4

5 回答 5

14

您不应任何第三方 jar 作为 uber jar 捆绑到您自己的 jar 中,但最好将分发中所需的所有 jar 的副本包含在 lib 目录或其他任何目录中。

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

还有一种选择,那就是使用类似maven shade 插件的东西将你的依赖项重新定位到你自己的包命名空间中。这当然有不利的一面,您会增加库的代码大小,但有利的一面是,您几乎可以保证依赖项的版本,而不会影响您的客户可能正在使用的任何其他库。

编辑:回应马库斯莱昂评论:

没有捆绑/搬迁的可能解决方案:

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

最后,实际上很难确保您拥有所需的依赖项,因为 java 是一种后期绑定的语言,您的依赖项(即使捆绑)可能会被包含在类路径上的不同版本的人覆盖。

注意:我最近度过了非常糟糕的一天,试图找出为什么我们的一个应用程序未能找到新版本的 log4j。原因:有人试图提供帮助,把它捆绑到一个随机的完全不相关的罐子里。

于 2009-11-17T08:10:44.160 回答
7

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

于 2009-11-17T03:34:10.147 回答
4

捆绑到单个 jar 中的优点显然是:

  • 客户的简单性

捆绑的缺点是:

  • 无法更新依赖库的版本
  • 隐藏必要的库实际上会导致客户端与那些额外的库发生潜在冲突
  • 构建过程中的复杂性(但在 Ant/Maven 中很容易做到这一点的方法)
  • 一些带有清单的库不能只是 unjared 和 rejared - 您需要实际合并清单信息。不过,Ant 和 Maven 对此提供了支持。

另一种选择是使用单个主 jar(您的代码)并设置类路径清单属性来吸收其他 jar。我个人不喜欢这样,因为很容易错过这些半隐藏的依赖关系。

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

于 2009-11-17T04:10:41.960 回答
2

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

于 2009-11-17T03:10:38.717 回答
0

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

如果您知道一个包需要作为更大平台的一部分工作(例如,作为可能加载自己的 jar 的框架的插件),那么您确实需要更强大的 OSGI 多版本类加载(又名 JSR -291): OSGI 技术

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

于 2009-12-03T20:31:23.060 回答