生产者与消费者

Gradle 依赖管理的一个关键概念是消费者和生产者之间的区别。

当您构建库时,您实际上是生产者一方:您正在生产将被其他人(即消费者)使用的工件

传统构建系统的许多问题是它们无法区分生产者和消费者。

消费者需要从广义上理解:

  • 依赖于另一个项目的项目是消费者

  • 依赖于工件的任务是更细粒度的消费者

在依赖管理中,我们做出的很多决策取决于我们正在构建的项目类型,也就是说,我们是哪种消费者

生产者变种

生产者可能希望为不同类型的消费者生成不同的工件:对于相同的源代码,会生成不同的二进制文件。或者,一个项目可能会生成供其他项目(同一存储库)使用但不供外部使用的工件。

Java 世界中的一个典型例子是 Guava 库,它发布了不同的版本:一个用于 Java 项目,一个用于 Android 项目。

但是,消费者有责任告知要使用哪个版本,依赖管理引擎有责任确保图的一致性(例如,确保您的类路径上不会同时出现 Java 和 Android 版本的 Guava) 。这就是Gradle变体模型发挥作用的地方。

在 Gradle 中,生产者变体通过消耗品配置公开。

封装性强

为了让生产者编译库,它需要编译类路径上的所有实现依赖项。有些依赖项仅需要作为库的实现细节,有些库实际上是 API 的一部分。

然而,依赖于这个生成的库的库只需要“查看”您的库的公共 API 以及该 API 的依赖项。它是生产者的编译类路径的子集:这是依赖项的强封装。

结果是分配给implementation库配置的依赖项不会最终出现在使用者的编译类路径上。另一方面,分配给api库配置的依赖项最终将出现在消费者的编译类路径上。然而,在运行时,所有依赖项都是必需的。即使在单个项目中,Gradle 也会区分不同类型的使用者:例如,Java 编译任务与 Java 执行任务是不同的使用者。

有关 Java 世界中 API 和运行时依赖项隔离的更多详细信息,请参见此处

尊重消费者

作为开发人员,每当您决定包含依赖项时,您都必须了解这会给您的消费者带来后果。例如,如果您向项目添加依赖项,它就会成为使用者的传递依赖项,因此如果使用者需要不同的版本,则可能会参与冲突解决。

Gradle 处理的许多问题都是为了解决消费者和生产者期望之间的不匹配问题。

然而,有些项目比其他项目更容易:

  • 如果您位于消费链的末端,也就是说您构建了一个应用程序,那么您的项目实际上没有消费者(除了最终客户):添加排除项除了解决您的问题之外不会有任何其他后果。

  • 但是,如果您是一个图书馆,添加排除项可能会阻止使用者正常工作,因为他们会使用您不使用的代码路径

请始终记住,您选择解决问题的解决方案可能会“泄漏”给您的消费者。本文档旨在指导您找到正确问题的正确解决方案,更重要的是,做出有助于解决引擎在发生冲突时做出正确决策的决策。