领先一步
VMware 提供培训和认证,助您加速进步。
了解更多我们在 Spring Boot 2.3.0.M1 中做了一个相当重大的改变。这是该项目首次使用 Gradle 而不是 Maven 进行构建。在 Twitter 上的一个帖子 中,许多人询问我们为什么切换以及我们看到的好处。这篇博客文章旨在回答这些问题。
Spring 产品组合中的每个项目都是以相当自主的方式运行的。我们在用户最能感受到的地方——例如 API 设计——力求一致性,但对于不那么显眼的事情,我们选择最能满足项目需求的工具。构建系统就是一个例子。构建系统的更改会影响项目贡献者,但如果我们做得对,它对用户没有任何影响。这导致了 Maven 和 Gradle 构建混合使用的情况。例如,Spring Framework 自 2012 年的 3.2.0.M1 版本以来一直使用 Gradle 构建,而 Spring Boot 和 Spring Cloud 则在那之后不久开始,两者都使用 Maven 构建。与 Spring Boot 不同,Spring Cloud 没有计划切换,因为 Maven 仍然满足他们的需求。总之,如果您只从这篇博客文章中获取一件事,那就是您应该选择最适合您项目需求的工具。
Spring Boot 团队考虑切换到 Gradle 的主要原因是缩短项目构建时间。我们对修改和测试更改时的反馈循环长度感到沮丧。等待构建完成的时间增加了修复 bug 和实现新功能所需的时间。我们在其他 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 里程碑、其发布候选版本和最终版本后,看起来我们成功了。我们没有在核心团队或任何其他贡献者那里看到任何主要的构建问题。
Spring Boot 的一个关键特性是约定优于配置,我们也将其应用于构建。遵循 避免在 build.gradle 文件中包含命令式逻辑 的建议,我们编写了几个小的插件,可以在项目的 buildSrc 中找到。例如,我们有一个 starter 插件,它应用于每个 Spring Boot starter 模块,确保它们都以一致的方式进行配置、构建和发布。我们还有一个 conventions 插件,它响应其他插件的应用,并配置如源代码编码、JUnit Platform 的使用以及使用 -parameters 进行编译等内容。
这种方法使得 build.gradle 文件几乎完全是声明式的。尽管我们编写了许多插件来应用我们的约定并填补 Gradle 生态系统的空白,但 迁移到 Gradle 的提交 从代码库中删除了近 9500 行代码。
在减少项目构建时间方面,将构建迁移到 Gradle 无疑是成功的。如上所述,一个完整的基于 Maven 的构建在 CI 和开发人员自己的机器上都需要一个小时或更长时间。在过去的四周里,使用 Gradle 的平均成功构建时间为 9 分 22 秒,如下面的截图所示。

我们从 JDK 8 CI 构建中发布快照。聚焦于这些,在过去四周内已成功 183 次,平均构建时间为 19 分 37 秒。查看成功的本地构建,我们可以看到在过去四周内有 273 次成功的构建,平均构建时间为 2 分 30 秒。
吸引我们转向 Gradle 的另一个好处是 我 在为 Testcontainers 做贡献时所获得的体验。我们也希望 Spring Boot 的贡献者能够尽快克隆和构建项目。得益于远程构建缓存,一个干净的签出可以在 3 分钟内完成构建。这包括下载大量依赖项所需的时间。
如果您对构建性能有更多兴趣,可以在我们的公共 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 用户,请继续使用并支持对您来说效果良好的工具。