Producers vs consumers

Gradle依赖管理中的一个关键概念是在消费者和生产者之间产生差异.

当你建立一个库,有效地都在制片方:你是生产这些要由别人, 消费者 消费 的文物 .

传统构建系统存在许多问题,即它们无法在生产者和消费者之间发挥作用.

需要从广义上理解消费者

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

  • 依赖人工制品的任务是更细粒度的消费者

在依赖管理中,我们做出的许多决定取决于我们正在构建的项目的类型,即我们是什么样的消费者 .

Producer variants

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

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

但是,消费者的责任是告知要使用的版本,并且依赖关系管理引擎的责任是确保图的一致性 (例如,确保在类路径中不使用Guava的Java和Android版本) . 这就是Gradle 变体模型发挥作用的地方.

在Gradle中, 生产者变体通过耗材配置公开.

Strong encapsulation

为了使生产者可以编译库,它需要所有实现依赖于编译类路径. 存在仅作为的实现细节所需的依赖关系,并且某些库实际上是API的一部分.

但是, 依赖于此生成的库的库仅需要"查看"库的公共API,因此也可以"查看"该API的依赖项. 它是生产方的编译类路径的子集:这是对依赖性的强封装.

结果是,分配给库的implementation配置的依赖项不会最终出现在使用者的编译类路径上 . 另一方面,分配给库的api配置的依赖项将最终出现在使用者的编译类路径上 . 但是,在运行时 ,需要所有依赖项. 即使在单个项目中,Gradle也会在不同类型的使用者之间产生差异:例如,Java编译任务与Java exec任务是不同的使用者.

在Java世界中可以找到有关API和运行时依赖项分离的更多详细信息.

Being respectful of consumers

无论何时,作为开发人员,您决定包括依赖项时,您都必须了解对消费者有影响 . 例如,如果将依赖项添加到项目中,则它将成为使用者的传递性依赖项,因此,如果使用者需要其他版本,则可能会参与冲突解决.

Gradle处理的许多问题都与解决消费者和生产者的期望之间的不匹配有关.

但是,有些项目比其他项目容易:

  • 如果您处于消费链的末端,也就是说您正在构建应用程序 ,那么实际上没有项目的使用者 (最终用户除外 ):添加排除项只会解决您的问题.

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

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