Spring/Spring Boot编译工具从Maven迁移到了Gradle

Spring/Spring Boot编译工具从Maven迁移到了Gradle

如果您正在考虑从 Maven 迁移到 Gradle,我希望了解更多有关 Spring Boot 团队的经验是有用的。 如果你是一个快乐的Maven 用户,请继续使用和支持适合你的工具。

原文地址:https://spring.io/blog/2020/06/08/migrating-spring-boot-s-build-to-gradle

image.png

我们在 2.3.0.M1 中对 Spring Boot 进行了相当大的改变。 这是使用 Gradle 而不是 Maven 构建的项目的第一个版本。 关于迁移的 Twitter 上的帖子 有很多人问我们为什么切换以及我们看到的好处(如果有的话)。 这篇博文旨在回答这些问题。

Spring 产品套件中的每个项目都以相当自主的方式运行。 我们力求在用户最容易看到的地方保持一致性--例如 API 设计,但选择最能满足项目需求的工具就不太明显。 一个例子是构建系统。 对构建系统的改变会影响那些为项目做出贡献的人,但如果我们做对了,它对用户是没有影响的。 这导致混合了基于 Maven 和 Gradle 的构建。 例如,自 2012 年 3.2.0.M1 以来,Spring Framework就一直使用 Gradle 构建;而 Spring Boot一年后诞生的,Spring Cloud也在此后不久开始,两者当时都使用基于 Maven 的构建。 与 Spring Boot 不同的是,Spring Cloud目前没有切换的计划,因为Maven满足他们的需求。 简而言之,如果您从这篇博文中只得到一件事,那就是您应该选择最能满足您项目需求的任何工具。

我们为什么要切换?

Spring Boot 团队考虑切换到Gradle的主要原因是减少构建项目所需的时间。 在进行测试修改时,我们对反馈循环的长度感到沮丧。 等待构建完成所花费的时间增加了修复错误和实现新功能所花费的时间。 我们在其他Spring 项目中看到了Gradle 的增量和并行构建以及在第三方项目中的 Gradle 构建缓存的好处。 我们希望我们可以在 Spring Boot 的构建中获得类似的好处。

我们过去曾尝试利用 Maven 对并行构建的支持。 由于 Spring Boot 构建的复杂性,尤其是对 Invoker 插件的使用,我们的尝试失败了。 我们通过在CI(持续集成)上将构建分成四个部分来解决这个问题。 该项目的主要核心是先构建的,然后并行构建三个独立的部分。 这种安排虽然有所帮助,但CI构建任务仍然需要一个小时或更长时间。 此外,由于拆分结构是特定于 CI 构建的,它并没有使开发人员的本地构建更快。

Gradle 有一个构建结构的广泛模型,了解每个任务的输入和输出及其相互依赖关系。 这种建模的承诺是它允许任务并行运行,同时也可以增量、缓存或完全避免。 换句话说,Gradle 旨在最大限度地减少构建任何给定更改所需的工作量,并行执行必要的工作。 如果我们坚持并广泛重组 Spring Boot 的构建,那么使用 Maven 并行构建可能是可行的。 而且,如果我们使用 Gradle Enterprise 的Maven支持,我们也可以享受构建缓存和避免的好处。 然而,为了充分享受这四个方面的好处,我们觉得我们必须尝试切换到 Gradle。

我们怎么切换?

我们看到的对 Gradle 的一种批评是,它导致构建比基于 Maven 的同类产品更难维护和理解。 Gradle的灵活性允许以微妙不同的方式完成任务,即使是在同一构建中的模块之间也是如此。 如果要成功切换,我们需要避免这种情况发生。 我们已经发布了四个Spring Boot 2.3 里程碑(候选版本和 Gradle 的最终版本),看起来已经成功了。 核心团队或任何其他贡献者都没有看到任何重大的构建问题。

Spring Boot 的一个关键特性是“约定优于配置”,我们也将这种方法应用于构建。遵循“ 避免在 build.gradle 文件中包含命令式逻辑 ”的建议,我们编写了几个可以找到的小插件在项目的 buildSrc中。例如我们有一个starter plugin 应用于每个 Spring Boot 启动模块,确保它们都被一致地配置、构建和发布。我们还有一个约定插件对正在应用的其他插件做出反应,并配置诸如源代码编码、JUnit 平台的使用以及使用-parameters编译等内容。

这种方法导致 build.gradle 文件几乎完全是声明性的。 尽管我们编写了许多插件来应用我们的约定并填补Gradle 生态系统中的空白, 但迁移到 Gradle 的提交 却从代码库中删除了近 9500 行。

切换有好处吗?

在减少项目的构建时间方面,将构建迁移到 Gradle 无疑是成功的。 如上所述,在 CI 和开发人员自己的机器上,一个完整的基于 Maven 的构建需要一个小时或更长时间。 在过去的四个星期里,使用 Gradle平均成功构建时间为 9 分 22 秒,如下面的屏幕截图所示:

image.png

我们从 JDK 8 CI 构建发布快照。 专注于那些,它在过去 4 周内成功了 183 次 与 平均构建 时间 19 分 37 秒。 查看成功的本地构建,我们可以看到:

过去 4 周内成功构建了 273 个

image.png

平均构建时间为 2 分 30 秒

image.png

Gradle 吸引我们的另一个好处是 我很享受 在为 Testcontainers 做贡献时的体验。 我们希望 Spring Boot 的贡献者能够尽快克隆和构建项目。 感谢远程构建缓存,可以 3 分钟内构建完成,这包括下载大量依赖项所花费的时间。

image.png

如果您对构建性能的更多细节感兴趣,可以在我们的公共 Gradle Enterprise 实例 上获得更多数据。

除了性能改进之外,我们还开始研究其他一些可用的数据。例如,我们已经意识到我们有一些不稳定的测试一段时间了。由于它们,构建失败的频率超出了我们的预期,我们现在可以在 Tests dashboard中看到这一点。我们已经开始使用 Gradle 的易碎测试缓解来识别 CI 上发生的任何易碎测试帮助我们了解我们是否已成功解决或解决问题。

结论

我们对迁移的进展以及我们所看到的构建时间的减少感到非常满意。 CI 构建现在平均需要大约 20 分钟,比以前快 3-4 倍。 本地构建平均需要 2 分 30 秒,比以前快 20-30 倍。

我想借此机会感谢 Gradle 团队在迁移过程中提供的帮助,并慷慨地为我们提供了 Gradle Enterprise 许可证以用于我们的开源项目。 我们已经将它与 Spring Framework、Spring Security 和 Spring Boot 一起使用,其他团队计划开始将它用于基于 Gradle 和 Maven 的构建。

我还要感谢我们正在使用的各种第三方插件的维护者。 他们提出了建议的更改并合并了拉取请求,以改进对增量构建和缓存的支持。 没有它们,我们将无法实现我们所看到的构建时间的减少。

如果您正在考虑从 Maven 迁移到 Gradle,我希望了解更多有关 Spring Boot 团队的经验是有用的。 如果你是一个快乐的 Maven 用户,请继续使用和支持适合你的工具。