AGP正确使用dependsOn

什么时候应该使用dependsOn?

简而言之,Gradle 通过计算任务依赖关系图来工作。假设您要构建一个 JAR 文件:您要调用 jar 任务,而 Gradle 将确定构建 jar,它需要编译类、处理资源等……确定任务依赖项,也就是说还需要执行哪些其他任务,是通过查看3个不同的东西来完成的:

任务取决于依赖项。例如,assemble.dependsOn(jar) 表示如果运行assemble,那么jar任务必须先执行

任务传递依赖关系,在这种情况下,我们不是在谈论任务,而是在谈论“出版物”。例如,当你需要编译项目 A 时,你需要在 classpath 项目 B 上,这意味着运行 B 的一些任务。

最后但并非最不重要的是,任务输入,也就是说,它需要什么来执行它的工作 

看看下面的代码: image.png

用与其他构建工具(如 Maven 或 Ant)相同的方式思考是很诱人的,尤其是当您不习惯 Gradle 时。你在想“有一个任务,jar,它基本上将它在 classes/groovy/main 中找到的所有内容打包,所以如果我想在 jar 任务中添加更多内容,让我们在 classes/groovy/main 中添加更多内容” .

由于不同的原因,这是错误的,最明显的是:

当 docsFilesJar 任务将被执行时,它会向“classes”目录贡献更多文件,但是,等等,那些不是我们放在那里的类,对吧?它只是一个罐子,资源。我们不应该改用 resources/groovy/main 吗?或者是classes/groovy/resources?要不然是啥?好吧,你不应该关心,因为你不关心 Java 编译任务将其输出放在哪里!

它破坏了可缓存性:Gradle 有一个构建缓存,多个任务贡献于同一个输出目录是破坏缓存的典型示例。事实上,它打破了各种最新的检查,也就是说,Gradle 能够理解它不需要在没有任何变化的情况下执行任务。

它对 Gradle 是不透明的:上面的代码在 doLast 块中执行一个副本。没有什么能告诉 Gradle “类”有额外的输出。

想象另一个只需要类的任务。根据它执行的时间,它可能包含也可能不包含它不关心的 docsFileJar。这使得构建不可重现(请注意,这正是 Maven 构建不可信并且您需要运行干净的原因,因为任何“目标”可以随时写入任何目录,因此无法推断谁贡献了什么)。

它需要声明 jar 任务和 docsFileJar 任务之间的显式依赖关系,以确保如果我们执行 jar,我们的“docs jar”文件存在

它没有说明为什么会有依赖关系:是因为你想订购东西,还是因为你需要依赖任务产生的工件?还有什么?

很容易忘记这些:因为您可能经常运行构建,您可能认为您的构建工作,因为 jar 是任务图的一部分,并且偶然地,docsFileJar 会在之前执行

它会产生意外的额外工作:大多数情况下,dependsOn 会触发过多的工作。 Gradle 是一个智能构建工具,它可以精确计算每个特定任务需要执行的内容。通过使用dependsOn,你有点像使用锤子并强迫它在图中整合一些不必要的东西。简而言之:你做的工作太多了。

很难摆脱它们:当您看到dependsOn时,因为它没有说明为什么需要它,因此在优化构建时通常很难摆脱这种依赖关系

改用隐式依赖!

我们的问题的答案实际上更容易推理:颠倒逻辑。与其想“我应该把这些东西放在哪里,以便被 jar 拾取”,不如想想“让我们告诉 jar 任务它也需要拾取我的资源”。

总而言之,这是关于正确声明您的任务输入。

与其修补另一个任务的输出(说真的,忘记这个!),每个任务都必须被认为是一个接受输入并产生输出的函数:它是隔离的。那么,我们的 docsFileJar 的输入是什么?我们要打包的资源。它的输出是什么?罐子本身。没有关于我们应该把罐子放在哪里的问题,我们让 Gradle 为我们选择了一个合理的地方。

那么 jar 任务本身的输入是什么?好吧,这是常规输入加上我们的 jar。它更容易推理,而且作为奖励,它甚至更短!

因此,让我们将上面的代码重写为:

image.png

您看得出来差别吗?我们摆脱了 docFilesJar 任务中的副本,我们不想这样做。相反,我们想要的是说“当你构建 jar 时,还要选择这个 docsFileJar。这就是我们通过 docsFileJar 告诉我们正在做的事情。Gradle 足够聪明,知道它什么时候需要执行 jar 任务,首先,它需要构建 docsFilesJar。

这样做有几个优点:

  • 依赖变得隐含:如果我们不想再包含 jar,我们只需将其从输入规范中删除即可。
  • 它不会污染其他任务的输出
  • 可以独立于 jar 执行 docsFileJar
  • 总而言之,这是为了将事物彼此隔离并降低意外破坏构建的风险!

上面的代码可以工作,但它有一个缺点:即使我们调用不需要的东西,docFilesJar 和 jar 任务也会被配置(实例化)。例如,假设您调用 gradle compileJava:没有理由在那里配置 jar 任务,因为我们不会执行它们。

image.png

作为结论:

尽可能避免使用显式的dependsOn

我倾向于说dependsOn唯一合理的用例是生命周期任务(生命周期任务是目标只是“组织构建”的任务,例如构建,组装,检查:他们自己不做任何事情,他们只是将一些家属绑定在一起)

如果您发现用例不是生命周期任务并且不能通过隐式任务依赖项来表达(例如声明输入而不是依赖项),则将其报告给 Gradle 团队

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值