欢迎访问shiker.tech

请允许在我们的网站上展示广告

您似乎使用了广告拦截器,请关闭广告拦截器。我们的网站依靠广告获取资金。

【译文】maven项目迁移至gradle
(last modified Jun 26, 2023, 12:31 PM )
by
侧边栏壁纸
  • 累计撰写 192 篇文章
  • 累计创建 66 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

【译文】maven项目迁移至gradle

橙序员
2022-09-04 / 0 评论 / 0 点赞 / 1,011 阅读 / 9,808 字 / 正在检测百度是否收录... 正在检测必应是否收录...
文章摘要(AI生成)

Apache Maven是一个构建工具,适用于 Java 和其他广泛使用的基于 JVM 的项目,因此想要使用 Gradle 的人通常必须迁移现有的 Maven 构建。本指南将通过解释两种工具模型之间的差异和相似之处并提供您可以遵循以简化流程的步骤来帮助进行此类迁移。转换构建可能很可怕,但您不必独自完

Apache Maven是一个构建工具,适用于 Java 和其他广泛使用的基于 JVM 的项目,因此想要使用 Gradle 的人通常必须迁移现有的 Maven 构建。本指南将通过解释两种工具模型之间的差异和相似之处并提供您可以遵循以简化流程的步骤来帮助进行此类迁移。

转换构建可能很可怕,但您不必独自完成。您可以从help.gradle.org搜索文档、论坛和 StackOverflow,如果遇到困难,也可以联系论坛上的Gradle 社区

Gradle 和 Apache Maven 的区别

下面总结一下 Gradle 和 Apache Maven 的主要区别:灵活性、性能、用户体验和依赖管理。它并不详尽,但您可以查看Gradle 功能列表Gradle 与 Maven 性能比较以了解更多信息。

img此 GIF 显示了使用 Maven 和 Gradle(没有构建缓存)的Apache Commons Lang 库的并行干净构建。您可以在此处查看构建

灵活性

Google 选择 Gradle 作为Android 的官方构建工具;不是因为构建脚本是代码,而是因为 Gradle 以最基本的方式可扩展的方式建模。Gradle 的模型还允许它用于使用 C/C++ 进行本机开发,并且可以扩展以覆盖任何生态系统。例如,Gradle 的设计考虑到了使用其Tooling API的嵌入。

Gradle 和 Maven 都提供了约定优于配置。然而,Maven 提供了一个非常僵化的模型,这使得定制变得乏味,有时甚至是不可能的。虽然这可以更容易地理解任何给定的 Maven 构建,但只要您没有任何特殊要求,它也会使其不适用于许多自动化问题。另一方面,Gradle 的构建考虑了授权和负责任的用户。

表现

image-20220904172005144

缩短构建时间是加快交付速度的最直接方法之一。Gradle 和 Maven 都采用某种形式的并行项目构建和并行依赖解析。最大的不同是 Gradle 的工作回避和增量机制。使 Gradle 比 Maven 快得多的前 3 个特性是:

  • 增量——Gradle 通过跟踪任务的输入和输出来避免工作,只运行必要的,并且只处理可能发生变化的文件
  • 构建缓存——重用任何其他具有相同输入的 Gradle 构建的构建输出,包括在机器之间。
  • Gradle Daemon — 一个长期存在的进程,可在内存中保持构建信息“热”。

在Gradle 与 Maven 性能比较中,这些以及更多性能特性使 Gradle 在几乎所有场景中的速度至少提高了两倍(使用构建缓存的大型构建速度提高了 100 倍)。

注意: Gradle 和 Maven 用户都可以利用 Gradle Enterprise 中提供的构建缓存技术。Gradle 用户通常会额外减少约 50% 的构建时间,而 Maven 用户通常会减少约 90%。 观看此视频以了解有关 Gradle Enterprise Maven 构建缓存技术和业务案例的更多信息。

用户体验

在 IDE 中使用 Kotlin 编写的 Gradle 构建脚本

Maven 更长的任期意味着它通过 IDE 的支持对许多用户来说更好。然而,Gradle 的 IDE 支持继续快速改进。例如,Gradle 现在有一个基于 Kotlin 的 DSL,可以提供更好的 IDE 体验。Gradle 团队正在与 IDE 制造商合作,以更好地支持编辑 -请继续关注更新。

尽管 IDE 很重要,但大量用户更喜欢通过命令行界面执行构建操作。Gradle 提供了一个现代 CLI,它具有诸如“gradle 任务”之类的可发现性功能,以及改进的日志记录和命令行完成功能

最后,Gradle 提供了一个基于 Web 的交互式 UI,用于调试和优化构建:Build Scan™。这些也可以在本地托管,以允许组织收集构建历史并进行趋势分析、比较构建以进行调试或优化构建时间。

构建扫描™

依赖管理

两种构建系统都提供内置功能来解决可配置存储库的依赖关系。两者都能够在本地缓存依赖项并并行下载它们。

作为库使用者,Maven 允许覆盖依赖项,但仅限于版本。Gradle 提供可自定义的依赖选择替换规则,可以声明一次并在项目范围内处理不需要的依赖。这种替换机制使 Gradle 能够一起构建多个源项目以创建复合构建

Maven 几乎没有内置的依赖范围,这会在使用测试夹具或代码生成等常见场景中强制使用笨拙的模块架构。例如,单元测试和集成测试之间没有分离。Gradle 允许自定义依赖范围,这提供了更好的建模和更快的构建。

Maven 依赖冲突解决使用最短路径,它受声明顺序的影响。Gradle 执行完全冲突解决,选择图中找到的依赖项的最高版本。此外,使用 Gradle,您可以严格声明版本,这允许它们优先于传递版本,从而允许降级依赖

作为库生产者,Gradle 允许生产者声明 apiimplementation 依赖项,以防止不需要的库泄漏到消费者的类路径中。Maven 允许发布者通过可选的依赖项提供元数据,但仅作为文档。Gradle 完全支持功能变体和可选依赖项。

MAVEN迁移到gradle

提出迁移的理由

Gradle 和 Maven 之间的主要区别在于灵活性、性能、用户体验和依赖管理

从 Gradle 3.0 开始,Gradle 投入巨资使 Gradle 构建速度更快,具有构建缓存编译避免和改进的增量 Java 编译器等功能。对于绝大多数项目,Gradle 现在比 Maven 快 2-10 倍,即使不使用构建缓存也是如此。可以在此处找到从 Maven 切换到 Gradle 的深入性能比较和业务案例。

一般准则

Gradle 和 Maven 对于如何构建项目有着根本不同的看法。Gradle 提供了一个灵活且可扩展的构建模型,它将实际工作委托给任务依赖关系图。Maven 使用固定的线性阶段模型,您可以将目标(完成工作的事物)附加到该阶段。这可能使两者之间的迁移看起来令人生畏,但迁移可能非常容易,因为 Gradle 遵循许多与 Maven 相同的约定——例如标准项目结构 ——并且它的依赖管理以类似的方式工作。

在这里,我们列出了一系列步骤供您遵循,这将有助于促进将任何 Maven 构建迁移到 Gradle:

保持旧的 Maven 构建和新的 Gradle 构建并排。您知道 Maven 构建可以正常工作,因此您应该保留它,直到您确信 Gradle 构建会生成所有相同的工件并且可以满足您的需要。这也意味着用户可以尝试 Gradle 构建,而无需获取源树的新副本。

  1. 为 Maven 构建创建构建扫描

    构建扫描将使您更容易可视化现有 Maven 构建中发生的情况。对于 Maven 构建,您将能够看到项目结构、正在使用的插件、构建步骤的时间表等等。保持方便,以便您可以将其与转换项目时获得的 Gradle 构建扫描进行比较。

  2. 开发一种机制来验证两个构建是否产生相同的工件

    这是确保您的部署和测试不会中断的至关重要的一步。即使是很小的更改,例如 JAR 中清单文件的内容,也可能导致问题。如果您的 Gradle 构建产生与 Maven 构建相同的输出,这将使您和其他人有信心切换并更容易实施将提供最大好处的重大更改。

    这并不意味着您需要在每个阶段验证每个工件,尽管这样做可以帮助您快速确定问题的根源。您可以只关注关键输出,例如最终报告和已发布或部署的工件。

    与 Maven 相比,您需要考虑 Gradle 生成的构建输出的一些内在差异。生成的 POM 将仅包含消费所需的信息,并且它们将针对该场景正确使用<compile>和范围。<runtime>您可能还会看到档案中的文件顺序和类路径中的文件顺序不同。大多数差异都是良性的,但值得识别它们并验证它们是否正常。

  3. 运行自动转换

    这将创建您需要的所有 Gradle 构建文件,即使对于多模块构建也是如此。对于更简单的 Maven 项目,Gradle 构建将可以运行!

  4. 为 Gradle 构建创建构建扫描

    构建扫描将更容易可视化构建中发生的事情。对于 Gradle 构建,您将能够看到项目结构、依赖项(常规和项目间的)、正在使用的插件以及构建的控制台输出。

    此时您的构建可能会失败,但没关系;扫描仍将运行。将 Gradle 构建的构建扫描与 Maven 构建的构建扫描进行比较,然后继续查看此列表以排除故障。

    我们建议您在迁移期间定期生成构建扫描,以帮助您识别和解决问题。如果您愿意,您还可以使用 Gradle 构建扫描来确定提高构建性能的机会,毕竟性能是首先切换到 Gradle 的一个重要原因。

  5. 验证您的依赖关系并解决任何问题

  6. 配置集成和功能测试

    许多测试可以通过配置额外的源集来简单地迁移。如果您使用第三方库,例如FitNesse ,请查看Gradle 插件门户上是否有合适的社区插件可用。

  7. 用 Gradle 等价物替换 Maven 插件

    对于流行的插件,Gradle 通常有一个等效的插件可供您使用。您可能还会发现可以使用内置 Gradle 功能替换插件。作为最后的手段,您可能需要通过您自己的自定义插件和任务类型重新实现一个 Maven 插件。

本章的其余部分更详细地介绍了将构建从 Maven 迁移到 Gradle 的特定方面。

了解构建生命周期

Maven 构建基于构建生命周期的概念,该生命周期由一组固定阶段组成。这可能会成为用户迁移到 Gradle 的障碍,因为它的构建生命周期有所不同,尽管了解 Gradle 构建如何适应初始化、配置和执行阶段的结构很重要。幸运的是,Gradle 有一个可以模仿 Maven 阶段的特性:生命周期任务

这些允许您通过创建仅依赖于您感兴趣的任务的无操作任务来定义自己的“生命周期”。并且为了使 Maven 用户更容易过渡到 Gradle,基础插件 ——适用于所有 JVM 语言Java Library Plugin之类的插件 ——提供一组对应于主要 Maven 阶段的生命周期任务。

以下是一些主要 Maven 阶段和它们映射到的 Gradle 任务的列表:

  • clean

    使用cleanBase Plugin 提供的任务。

  • compile

    使用Java Plugin和其他 JVM 语言插件classes提供的任务。这将为所有语言的所有源文件编译所有类,并通过任务执行资源过滤。processResources

  • test

    使用testJava Plugin 提供的任务。它只运行单元测试,或者更具体地说,构成test源集的测试。

  • package

    使用assembleBase Plugin 提供的任务。这将为项目构建任何合适的包,例如用于 Java 库的 JAR 或用于传统 Java webapps 的 WAR。

  • verify

    使用checkBase Plugin 提供的任务。这会运行附加到它的所有验证任务,通常包括单元测试、任何静态分析任务(例如Checkstyle )和其他任务。如果要包括集成测试,则必须手动配置这些,这是一个简单的过程。

  • install

    使用Maven Publish PluginpublishToMavenLocal提供的任务。请注意,Gradle 构建不需要您“安装”工件,因为您可以访问更合适的功能,例如项目间依赖关系复合构建。您应该只publishToMavenLocal用于与 Maven 构建的互操作。Gradle 还允许您解决对本地 Maven 缓存的依赖关系,如声明存储库部分中所述。

  • deploy

    使用Maven 发布插件publish提供的任务—如果您的构建使用的是 旧的 Maven 插件 (ID: ),请确保您切换到该插件。这会将您的包发布到所有已配置的发布存储库。即使定义了多个存储库,也有其他任务允许您发布到单个存储库。maven请注意,默认情况下, Maven 发布插件不发布源代码和 Javadoc JAR ,但可以按照构建 Java 项目的指南中的说明轻松激活。

执行自动转换

Gradle 的init任务通常用于创建新的骨架项目,但您也可以使用它来自动将现有的 Maven 构建转换为 Gradle。在您的系统上安装Gradle后,您所要做的就是运行命令

> gradle init

从根项目目录中,让 Gradle 做它的事情。这基本上包括解析现有的 POM 和生成相应的 Gradle 构建脚本。如果您正在迁移多项目构建, Gradle 还将创建一个设置脚本。

您会发现新的 Gradle 构建包括以下内容:

  • POM 中指定的所有自定义存储库
  • 您的外部和项目间依赖关系
  • 构建项目的适当插件(仅限于Maven PublishJavaWar插件中的一个或多个)

有关自动转换功能的完整列表,请参阅Build Init Plugin 一章

要记住的一件事是程序集不会自动转换。转换它们不一定有问题,但您需要做一些手动工作。选项包括:

如果您的 Maven 构建没有很多插件或自定义方式,您可以简单地运行

> gradle build

迁移完成后。这将运行测试并生成所需的工件,而无需您进行任何额外的干预。

迁移依赖项

Gradle 的依赖管理系统比 Maven 的更灵活,但它仍然支持相同的存储库、声明的依赖、范围( Gradle 中的依赖配置)和传递依赖的概念。事实上,Gradle 与 Maven 兼容的存储库完美配合,这使得迁移依赖项变得容易。

这两种工具之间的一个显着区别在于它们如何管理版本冲突。Maven 使用“最接近”的匹配算法,而 Gradle 选择最新的。不过不用担心,您可以很好地控制选择哪些版本,如管理传递依赖项中所述。

在以下部分中,我们将向您展示如何迁移 Maven 构建的依赖管理信息中最常见的元素。

声明依赖

Gradle 使用与 Maven 相同的依赖标识符组件:组 ID、工件 ID 和版本。它还支持分类器。因此,您需要做的就是将依赖项的标识符信息替换为 Gradle 的语法,这在声明依赖项一章中进行了描述。

例如,考虑一下对 Log4J 的这种 Maven 风格的依赖:

<dependencies>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
</dependencies>

在 Gradle 构建脚本中,此依赖项如下所示:

示例 1. 声明一个简单的编译时依赖项

build.gradle

dependencies {
    implementation 'log4j:log4j:1.2.12'  
}

将 Log4J 的 1.2.12 版附加到implementation配置(范围)

字符串标识符采用 , 和 的 Maven 值groupIdartifactId尽管versionGradle 将它们称为group,moduleversion

上面的例子提出了一个明显的问题:那个implementation配置是什么?它是Java Plugin提供的标准依赖配置之一,通常用作 Maven 默认compile作用域的替代品。

Maven 的作用域和 Gradle 的标准配置之间的一些差异归结为 Gradle 区分了构建模块所需的依赖项和构建依赖于它的模块所需的依赖项。Maven 没有这种区别,因此发布的 POM 通常包含库的使用者实际上并不需要的依赖项。

以下是主要的 Maven 依赖范围以及您应该如何处理它们的迁移:

  • compile

    Gradle 有两种配置可以用来代替compile作用域:implementationapi. 前者适用于任何应用 Java Plugin 的项目,而api仅适用于专门应用Java Library Plugin的项目。在大多数情况下,您应该只使用implementation配置,尤其是在构建应用程序或 webapp 时。但是,如果您正在构建一个库,您可以在构建 Java 库api的部分中了解应该使用哪些依赖项来声明。上面链接的 Java 库插件章节中提供了更多关于和之间差异的信息。api``implementation

  • runtime

    使用runtimeOnly配置。

  • test

    Gradle 区分编译项目测试所需的依赖项和仅运行它们所需的依赖项。应针对testImplementation配置声明测试编译所需的依赖项。那些只需要运行测试的应该使用testRuntimeOnly.

  • provided

    使用compileOnly配置。请注意,War 插件添加providedCompileprovidedRuntime依赖配置。它们的行为与 WAR 文件略有不同,compileOnly它们只是确保这些依赖项未打包在 WAR 文件中。但是,依赖项包含在运行时和测试运行时类路径中,因此如果这是您需要的行为,请使用这些配置。

  • import

    import范围主要在<dependencyManagement>块内使用,并且仅适用于仅 POM 的出版物。阅读使用物料清单部分以了解有关如何复制此行为的更多信息。您还可以指定对仅 POM 发布的常规依赖项。在这种情况下,在该 POM 中声明的依赖项被视为构建的正常传递依赖项。例如,假设您想使用groovy-allPOM 进行测试。<dependencies>它是一个仅 POM 的发布,在块中列出了自己的依赖项。Gradle 构建中的适当配置如下所示:示例 2. 使用 POM-only 依赖项Groovy``Kotlin构建.gradledependencies { testImplementation 'org.codehaus.groovy:groovy-all:2.5.4' }这样做的结果将是 POM 中的所有compileruntime范围依赖项都groovy-all被添加到测试运行时类路径中,而只有compile范围依赖项被添加到测试编译类路径中。与其他范围的依赖关系将被忽略。

声明存储库

Gradle 允许您从任何 Maven 兼容或 Ivy 兼容的存储库中检索声明的依赖项。与 Maven 不同,它没有默认存储库,因此您必须至少声明一个。为了获得与 Maven 构建相同的行为,只需在 Gradle 构建中配置Maven Central ,如下所示:

示例 3. 配置构建以使用 Maven Central

build.gradle

repositories {
    mavenCentral()
}

您还可以使用该repositories {}块来配置自定义存储库,如存储库类型一章中所述。

最后,Gradle 允许您解决对本地 Maven 缓存/存储库的依赖关系。这有助于 Gradle 构建与 Maven 构建互操作,但如果您不需要该互操作性,则不应该使用它。如果您想通过文件系统共享已发布的工件,请考虑使用URL配置自定义 Maven 存储库。file://

您可能也有兴趣了解 Gradle 自己的依赖项缓存,它的行为比 Maven 的更可靠,并且可以被多个并发 Gradle 进程安全使用。

控制依赖版本

传递依赖的存在意味着你可以很容易地在你的依赖图中得到同一个依赖的多个版本。默认情况下,Gradle 会在图中选择最新版本的依赖项,但这并不总是正确的解决方案。这就是为什么它提供了几种机制来控制解决给定依赖项的哪个版本。

在每个项目的基础上,您可以使用:

控制传递依赖一章中列出了更多专门的选项。

如果您想确保多项目构建中所有项目的版本一致性,类似于<dependencyManagement>Maven 中的块的工作方式,您可以使用Java Platform Plugin。这允许您声明一组可应用于多个项目的依赖项约束。您甚至可以将平台发布为 Maven BOM 或使用 Gradle 的元数据格式。有关如何执行此操作的更多信息,请参阅插件页面,特别是有关使用平台的部分,以了解如何将平台应用于同一构建中的其他项目。

排除传递依赖

Maven 构建使用排除项将不需要的依赖项(或不需要的依赖项版本)排除在依赖关系图中。您可以使用 Gradle 做同样的事情,但这不一定是正确的做法。Gradle 提供了可能更适合给定情况的其他选项,因此您确实需要了解为什么要正确迁移排除项。

如果您想排除与版本无关的依赖项,请查看dependency_downgrade_and_exclude.html部分。它向您展示了如何将排除附加到整个配置(通常是最合适的解决方案)或依赖项。您甚至可以轻松地将排除项应用于所有配置。

如果您对控制实际解析哪个版本的依赖项更感兴趣,请参阅上一节。

处理可选依赖项

关于可选依赖,您可能会遇到两种情况:

  • 您的一些传递依赖项被声明为可选
  • 您想在项目已发布的 POM 中将一些直接依赖项声明为可选

对于第一种情况,Gradle 的行为方式与 Maven 相同,只是忽略任何声明为可选的传递依赖项。如果相同的依赖关系在依赖关系图中的其他位置显示为非可选,则它们不会被解析并且对所选版本没有影响。

至于将依赖项发布为可选,Gradle 提供了一个更丰富的模型,称为功能变体,它可以让您声明库提供的“可选功能”。

使用物料清单 (BOM)

Maven 允许您通过在<dependencyManagement>打包类型为pom. 然后可以将这种特殊类型的 POM(BOM)导入其他 POM,以便您在项目中拥有一致的库版本。

Gradle 可以将此类 BOM 用于相同目的,使用基于platform()enforcedPlatform()方法的特殊依赖语法。您只需以正常方式声明依赖项,但将依赖项标识符包装在适当的方法中,如“导入”Spring Boot Dependencies BOM 的示例所示:

示例 4. 在 Gradle 构建中导入 BOM

build.gradle

dependencies {
    implementation platform('org.springframework.boot:spring-boot-dependencies:1.5.8.RELEASE') 

    implementation 'com.google.code.gson:gson' 
    implementation 'dom4j:dom4j'
}

应用 Spring Boot 依赖项 BOM

添加其版本由该 BOM 定义的依赖项

您可以在有关从 Maven BOM 导入版本建议的部分中了解有关此功能的更多信息以及两者之间的platform()区别。enforcedPlatform()

您可以使用此功能将<dependencyManagement>任何依赖项的 POM 中的信息应用于 Gradle 构建,即使是那些没有pom. 两者都platform()enforcedPlatform()忽略<dependencies>块中声明的任何依赖项。

迁移多模块构建(项目聚合)

Maven 的多模块构建很好地映射到 Gradle 的多项目构建。尝试相应的示例,了解如何设置基本的多项目 Gradle 构建。

要迁移多模块 Maven 构建,只需按照以下步骤操作:

  1. 创建一个匹配<modules>根 POM 块的设置脚本。

    例如,这个<modules>块:

    <modules>
        <module>simple-weather</module>
        <module>simple-webapp</module>
    </modules>
    

    可以通过将以下行添加到设置脚本来迁移:

    示例 5. 声明哪些项目是构建的一部分

    build.gradle

    rootProject.name = 'simple-multi-module'  
    
    include 'simple-weather', 'simple-webapp'  
    

    设置整个项目的名称

    配置两个子项目作为此构建的一部分

    **gradle projects**的输出

    > gradle projects
    
    ------------------------------------------------------------
    Root project 'simple-multi-module'
    ------------------------------------------------------------
    
    Root project 'simple-multi-module'
    +--- Project ':simple-weather'
    \--- Project ':simple-webapp'
    
    To see a list of the tasks of a project, run gradle <project-path>:tasks
    For example, try running gradle :simple-weather:tasks
    
  2. 用项目依赖替换跨模块依赖。

  3. 使用约定插件复制项目继承。

    这基本上涉及创建一个根项目构建脚本,将共享配置注入适当的子项目。

跨项目共享版本

如果你想复制在dependencyManagement根 POM 文件部分中声明依赖版本的 Maven 模式,最好的方法是利用java-platform插件。您需要为此添加一个专用项目并在构建的常规项目中使用它。有关此模式的更多详细信息,请参阅文档

迁移 Maven 配置文件和属性

Maven 允许您使用各种属性对构建进行参数化。有些是项目模型的只读属性,有些是用户在 POM 中定义的。它甚至允许您将系统属性视为项目属性。

Gradle 有一个类似的项目属性系统,尽管它区分了这些和系统属性。例如,您可以在以下位置定义属性:

  • 构建脚本
  • gradle.properties根项目目录中的文件
  • 目录中的一个gradle.properties文件$HOME/.gradle

这些并不是唯一的选择,所以如果您有兴趣了解更多关于如何以及在何处定义属性的信息,请查看构建环境一章。

您需要注意的一项重要行为是,当在构建脚本和其中一个外部属性文件中定义相同的属性时会发生什么:构建脚本值优先。总是。幸运的是,您可以模仿配置文件的概念来提供可覆盖的默认值。

这将我们带到了 Maven 配置文件。这些是基于环境、目标平台或任何其他类似因素启用和禁用不同配置的方法。从逻辑上讲,它们只不过是有限的“if”语句。而且由于 Gradle 有更强大的方法来声明条件,它不需要对配置文件有正式的支持(除了在依赖项的 POM 中)。正如您将看到的,您可以通过将条件与辅助构建脚本组合来轻松获得相同的行为。

假设您有不同的部署设置,具体取决于环境:本地开发(默认)、测试环境和生产环境。要添加类似配置文件的行为,您首先在项目根目录中为每个环境创建构建脚本:profile-default.gradleprofile-test.gradleprofile-prod.gradle. 然后,您可以根据您自己选择的项目属性有条件地应用其中一个配置文件脚本。

以下示例演示了使用名为的项目属性buildProfile和配置文件脚本的基本技术,这些脚本只需初始化一个名为的额外项目属性message

示例 6. 在 Gradle 中模仿 Maven 配置文件的行为

build.gradle

if (!hasProperty('buildProfile')) ext.buildProfile = 'default'  

apply from: "profile-${buildProfile}.gradle"  

tasks.register('greeting') {
    doLast {
        println message  
    }
}

profile-default.gradle

ext.message = 'foobar'  

profile-test.gradle

ext.message = 'testing 1 2 3'  

profile-prod.gradle

ext.message = 'Hello, world!'  

检查 (Groovy) 是否存在或绑定 (Kotlin)buildProfile项目属性
应用适当的配置文件脚本,使用buildProfile脚本文件名中的值
打印出message额外项目属性的值
初始化message额外的项目属性,然后可以在主构建脚本中使用其值

有了这个设置,您可以通过为您正在使用的项目属性传递一个值来激活其中一个配置文件—— buildProfile在这种情况下:

**gradle greeting**的输出

> gradle greeting
foobar

**gradle -PbuildProfile=test greeting**的输出

> gradle -PbuildProfile=test greeting
testing 1 2 3

您不仅限于检查项目属性。您还可以检查环境变量、JDK 版本、运行构建的操作系统或您能想象到的任何其他内容。

要记住的一件事是,高级条件语句使构建更难理解和维护,类似于它们使面向对象代码复杂化的方式。这同样适用于配置文件。Gradle 为您提供了许多更好的方法来避免大量使用 Maven 经常需要的配置文件,例如通过配置多个任务,这些任务是彼此的变体。查看Maven Publish Plugin创建的任务。publish PubName PublicationTo RepoName Repository

有关在 Gradle 中使用 Maven 配置文件的详细讨论,请查看这篇博文

过滤资源

Maven 有一个称为默认process-resources目标的阶段。resources:resources这使构建作者有机会对各种文件执行变量替换,例如 Web 资源、打包的属性文件等。

Gradle 的 Java 插件提供了一个processResources任务来做同样的事情。这是一个ProcessResources任务,它将文件从配置的资源目录 src/main/resources(默认情况下)复制到输出目录。与任何任务一样ProcessResourcesCopy您可以将其配置为执行文件过滤重命名内容过滤

例如,下面的配置将源文件视为GroovySimpleTemplateEngine模板,为这些模板提供versionbuildNumber属性:

示例 7. 通过processResources任务过滤资源的内容

build.gradle

processResources {
    expand(version: version, buildNumber: currentBuildNumber)
}

请参阅CopySpec的 API 文档以查看您可用的所有选项。

配置集成测试

许多 Maven 构建包含某种类型的集成测试,Maven 通过一组额外的阶段支持这些测试:pre-integration-testintegration-testpost-integration-testverify. 它还使用 Failsafe 插件代替 Surefire,因此失败的集成测试不会自动使构建失败(因为您可能需要清理资源,例如正在运行的应用程序服务器)。

正如我们在 Java 和 JVM 项目中的测试一章中所解释的那样,这种行为很容易在带有源集的 Gradle 中复制。然后,您可以使用Task.finalizedBy()配置清理任务,例如关闭测试服务器的清理任务,以始终在集成测试之后运行,无论它们是成功还是失败。

如果您真的不希望您的集成测试使构建失败,那么您可以使用Java 测试章节的测试执行部分中描述的Test.ignoreFailures设置。

源集还为您在放置集成测试源文件的位置提供了很大的灵活性。您可以轻松地将它们保存在与单元测试相同的目录中,或者更好地保存在单独的源目录中,例如src/integTest/java. 要支持其他类型的测试,您只需添加更多源集和测试任务!

迁移常用插件

Maven 和 Gradle 共享通过插件扩展构建的通用方法。尽管插件系统在表面下非常不同,但它们共享许多基于功能的插件,例如:

  • Shade/Shadow
  • Jetty
  • Checkstyle
  • JaCoCo
  • AntRun(见下文)

为什么这很重要?因为许多插件依赖于标准的 Java 约定,所以迁移只是复制 Gradle 中 Maven 插件的配置的问题。例如,这是一个简单的 Maven Checkstyle 插件配置:

...
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-checkstyle-plugin</artifactId>
  <version>2.17</version>
  <executions>
    <execution>
      <id>validate</id>
      <phase>validate</phase>
      <configuration>
        <configLocation>checkstyle.xml</configLocation>
        <encoding>UTF-8</encoding>
        <consoleOutput>true</consoleOutput>
        <failsOnError>true</failsOnError>
        <linkXRef>false</linkXRef>
      </configuration>
      <goals>
        <goal>check</goal>
      </goals>
    </execution>
  </executions>
</plugin>
...

迁移到 Gradle 时,可以安全地忽略配置块之外的所有内容。在这种情况下,对应的 Gradle 配置如下所示:

示例 8. 配置 Gradle Checkstyle 插件

build.gradle

checkstyle {
    config = resources.text.fromFile('checkstyle.xml', 'UTF-8')
    showViolations = true
    ignoreFailures = false
}

Checkstyle 任务会自动添加为任务的依赖check项,其中还包括test. 如果要确保 Checkstyle 在测试之前运行,则只需使用 mustRunAfter() 方法指定排序:

示例 9. 控制checkstyle任务何时运行

build.gradle

test.mustRunAfter checkstyleMain, checkstyleTest

如您所见,Gradle 配置通常比 Maven 等价物短得多。由于不再受 Maven 固定阶段的限制,您还拥有一个更加灵活的执行模型。

从 Maven 迁移项目时,不要忘记源集。这些通常为处理集成测试或生成的源提供了比 Maven 提供的更优雅的解决方案,因此您应该将它们纳入您的迁移计划。

ant目标

许多 Maven 构建依赖于 AntRun 插件来自定义构建,而无需实现自定义 Maven 插件的开销。Gradle 没有等效的插件,因为 Ant 是 Gradle 构建中的一等公民,通过ant对象。例如,您可以像这样使用 Ant 的 Echo 任务:

示例 10. 调用 Ant 任务

build.gradle

tasks.register('sayHello') {
    doLast {
        ant.echo message: 'Hello!'
    }
}

甚至原生支持 Ant 属性和文件集。要了解更多信息,请参阅从 Gradle 使用 Ant

仅创建自定义任务类型来替换 Ant 为您所做的工作可能更简单、更清晰。然后,您可以更轻松地从增量构建和其他有用的 Gradle 功能中受益。

了解您不需要哪些插件

值得记住的是,Gradle 构建通常比 Maven 更容易扩展和定制。在这种情况下,这意味着您可能不需要 Gradle 插件来替换 Maven 插件。例如,Maven Enforcer 插件允许您控制依赖版本和环境因素,但这些东西可以在普通的 Gradle 构建脚本中轻松配置。

处理不常见的和自定义的插件

您可能会遇到在 Gradle 中没有对应的 Maven 插件,特别是如果您或您组织中的某个人编写了自定义插件。这种情况取决于您了解 Gradle(可能还有 Maven)的工作原理,因为您通常必须编写自己的插件。

出于迁移的目的,有两种关键类型的 Maven 插件:

  • 那些使用 Maven 项目对象的。
  • 那些没有。

为什么这很重要?因为如果您使用后者之一,您可以轻松地将其重新实现为自定义 Gradle 任务类型。只需定义与 mojo 参数对应的任务输入和输出,并将执行逻辑转换为任务操作。

如果插件依赖于 Maven 项目,那么您将不得不重写它。不要从考虑 Maven 插件的工作原理开始,而是看看它试图解决什么问题。然后尝试找出如何在 Gradle 中解决该问题。您可能会发现这两种构建模型有很大的不同,以至于将 Maven 插件代码“转录”到 Gradle 插件中是无效的。从好的方面来说,该插件可能比原始的 Maven 更容易编写,因为 Gradle 具有更丰富的构建模型和 API。

如果您确实需要通过构建脚本或插件实现自定义逻辑,请查看[与插件开发相关的指南](https://gradle.org/guides/?q=Plugin Development)。此外,请务必熟悉 Gradle 的Groovy DSL 参考,它提供了有关您将使用的 API 的全面文档。它详细介绍了标准配置块(以及支持它们的对象)、系统中的核心类型(ProjectTask等)以及标准的任务类型集。主要入口点是Project接口,因为它是支持构建脚本的顶级对象。

0

评论区