💡
患有缓慢的Maven构建? 在此处注册以参加我们的构建缓存培训课程,以了解Gradle Enterprise如何将Maven构建速度提高多达90%.

Apache Maven是用于Java和其他基于JVM的项目的构建工具,这些项目已被广泛使用,因此想要使用Gradle的人们经常不得不迁移现有的Maven构建. 本指南将通过解释这两种工具的模型之间的差异和相似之处,并提供简化步骤可以帮助您进行迁移.

转换构建可能会很吓人,但您不必一个人做. 您可以从help.gradle.org搜索文档,论坛和StackOverflow,或者在遇到麻烦时访问Gradle社区 .

Making a case for migration

Gradle和Maven之间的主要区别是灵活性,性能,用户体验和依赖性管理. Maven与Gradle功能比较中提供了这些方面的直观概述.

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

General guidelines

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

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

💡
并排保留旧的Maven构建和新的Gradle构建. 您知道Maven构建可以工作,因此您应该保留它,直到您确信Gradle构建可以生成所有相同的工件,然后再做您需要的事情. 这也意味着用户可以在不获取源树的新副本的情况下尝试Gradle构建.
  1. Create a build scan for the Maven build .

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

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

    这是确保您的部署和测试不中断的至关重要的一步. 即使是很小的更改,例如JAR中清单文件的内容,也会引起问题. 如果您的Gradle构建生成的输出与Maven构建生成的输出相同,则这将使您和其他人对切换充满信心,并使更容易实施将带来最大收益的重大更改.

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

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

  3. Run an automatic conversion

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

  4. Create a build scan for the Gradle build.

    构建扫描将使可视化构建中的事情变得更加容易. 对于Gradle构建,您将能够查看项目结构,依赖关系(常规和项目间的依赖关系),正在使用的插件以及构建的控制台输出.

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

    我们建议您在迁移期间定期生成构建扫描,以帮助您确定问题并排除故障. 如果需要,您还可以使用Gradle构建扫描来确定提高构建性能的机会,毕竟,性能首先是切换到Gradle的主要原因.

  5. Verify your dependencies and fix any problems

  6. Configure integration and functional tests

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

  7. 用Gradle等效项替换Maven插件

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

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

Understanding the build lifecycle

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

这些使您可以通过创建仅依赖于您感兴趣的任务的无操作任务来定义自己的"生命周期".为了使Maven用户更轻松地过渡到Gradle, Base插件 -由所有JVM语言应用Java库插件之类的插件 —提供了一组与主要Maven阶段相对应的生命周期任务.

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

clean

使用基本插件提供的clean任务.

compile

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

test

使用Java插件提供的test任务. 它仅运行单元测试,或更具体而言,运行组成test源集test .

package

使用基本插件提供的assemble任务. 这将构建适合项目的任何软件包,例如Java库的JAR或传统Java Webapp的WAR.

verify

使用基本插件提供的check任务. 这将运行附加到它的所有验证任务,通常包括单元测试,任何静态分析任务(例如Checkstyle )以及其他任务. 如果要包括集成测试,则必须手动配置这些 ,这是一个简单的过程.

install

使用Maven发布插件提供的publishToMavenLocal任务.

请注意,Gradle构建不需要您"安装"工件,因为您可以访问更合适的功能,例如项目间依赖组合构建 . 您只应使用publishToMavenLocal与Maven构建进行互操作.

Gradle还允许您解析对本地Maven缓存的依赖关系,如" 声明存储库"部分中所述.

deploy

使用Maven Publish Plugin提供的publish任务-如果您的构建使用的是Maven插件,请确保从较早的Maven插件(ID: maven )切换. 这会将您的程序包发布到所有已配置的发布存储库. 即使定义了多个存储库,也有其他任务可以使您发布到单个存储库.

请注意, 默认情况下 ,Maven Publish Plugin不发布源代码和Javadoc JAR ,但是可以按照构建Java项目的指南中的说明轻松激活它.

Performing an automatic conversion

Gradle的init任务通常用于创建新的骨架项目,但是您也可以使用它将现有的Maven构建自动转换为Gradle. 将Gradle 安装到系统上后 ,只需执行以下命令

> gradle init

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

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

  • POM中指定的所有自定义存储库

  • 您的外部和项目间依赖性

  • 用于构建项目的适当插件(仅限于Maven PublishJavaWar插件中的一个或多个)

有关自动转换功能的完整列表,请参见Build Init插件一章 .

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

如果您的Maven构建没有很多插件或以自定义方式提供很多插件,则只需运行

> gradle build

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

Migrating dependencies

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

两种工具之间的显着区别是它们如何管理版本冲突. Maven使用"最接近"的匹配算法,而Gradle选择最新的匹配算法. 不过,请放心,您可以控制选择哪个版本,如管理传递依赖项中所述 .

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

Declaring dependencies

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'  // (1)
}
build.gradle.kts
dependencies {
    implementation("log4j:log4j:1.2.12")  // (1)
}
  1. 将Log4J版本1.2.12附加到implementation配置(作用域)

字符串标识符采用Maven的groupIdartifactIdversion ,尽管Gradle将它们称为groupmoduleversion .

上面的示例提出了一个明显的问题:该implementation配置是什么? 它是Java插件提供的标准依赖项配置之一,通常用于替代Maven的默认compile范围.

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

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

compile

Gradle具有两种可用于代替compile范围的配置: implementationapi . 前者适用于所有应用Java插件的项目,而api仅适用于专门应用Java库插件的项目 .

在大多数情况下,您应该只使用implementation配置,尤其是在构建应用程序或Webapp时. 但是,如果您要构建库,则可以在构建Java库一节中了解使用api声明哪些依赖项. 上面链接的" Java库插件"一章提供了有关apiimplementation之间区别的更多信息.

runtime

使用runtimeOnly配置.

test

Gradle区分了编译项目测试所需的那些依赖项和仅运行它们所需的那些依赖项.

应针对testImplementation配置声明测试编译所需的依赖关系. 仅运行测试所需的那些应该使用testRuntimeOnly .

provided

Use the compileOnly configuration.

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

import

import范围主要在<dependencyManagement>块内使用,并且仅适用于仅POM的发布. 阅读有关使用物料清单的部分,以了解有关如何复制此行为的更多信息.

您还可以指定对仅POM的发布的常规依赖性. 在这种情况下,在该POM中声明的依赖关系将被视为构建的常规传递依赖关系.

例如,假设您想在测试中使用groovy-all POM. 这是仅POM的出版物,在<dependencies>块中列出了自己的依赖项. Gradle构建中的适当配置如下所示:

示例2.消费仅POM依赖项
build.gradle
dependencies {
    testImplementation 'org.codehaus.groovy:groovy-all:2.5.4'
}
build.gradle.kts
dependencies {
    testImplementation("org.codehaus.groovy:groovy-all:2.5.4")
}

The result of this will be that all compile and runtime scope dependencies in the groovy-all POM get added to the test runtime classpath, while only the compile scope dependencies get added to the test compilation classpath. Dependencies with other scopes will be ignored.

Declaring repositories

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

示例3.将构建配置为使用Maven Central
build.gradle
repositories {
    mavenCentral()
}
build.gradle.kts
repositories {
    mavenCentral()
}

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

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

您可能还对了解Gradle自己的依赖项缓存感兴趣,后者比Maven的行为更可靠,并且可以被多个并发的Gradle进程安全地使用.

Controlling dependency versions

传递依赖项的存在意味着您可以轻松地在依赖关系图中最终获得同一依赖项的多个版本. 默认情况下,Gradle将选择图中的依赖项的最新版本,但这并不总是正确的解决方案. 这就是为什么它提供了几种机制来控制解决给定依赖项的哪个版本的原因.

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

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

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

Excluding transitive dependencies

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

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

If you’re more interested in controlling which version of a dependency is actually resolved, see the previous section.

Handling optional dependencies

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

  • 您的某些传递依赖项被声明为可选

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

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

至于将依赖项发布为可选的,Gradle提供了一个更丰富的模型,称为Feature Variants ,它可以让您声明库提供的"可选功能".

Using bills of materials (BOMs)

Maven允许您通过在包装类型为pom的POM文件的<dependencyManagement>部分内定义依赖项来共享依赖项约束. 然后可以将这种特殊类型的POM(物料清单)导入其他POM中,以便在项目中拥有一致的库版本.

Gradle can use such BOMs for the same purpose, using a special dependency syntax based on platform() and enforcedPlatform() methods. You simply declare the dependency in the normal way, but wrap the dependency identifier in the appropriate method, as shown in this example that "imports" the Spring Boot Dependencies BOM:

例子4.在Gradle版本中导入BOM
build.gradle
dependencies {
    implementation platform('org.springframework.boot:spring-boot-dependencies:1.5.8.RELEASE') // (1)

    implementation 'com.google.code.gson:gson' // (2)
    implementation 'dom4j:dom4j'
}
build.gradle.kts
dependencies {
    implementation(platform("org.springframework.boot:spring-boot-dependencies:1.5.8.RELEASE"))  // (1)

    implementation("com.google.code.gson:gson")  // (2)
    implementation("dom4j:dom4j")
}
  1. 应用Spring Boot Dependencies BOM

  2. 添加依赖项,其版本由该BOM表定义

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

您可以使用此功能将<dependencyManagement>信息从任何依赖项的POM应用于Gradle构建,即使那些没有pom打包类型的信息也是如此. platform()enforcedPlatform()都将忽略在<dependencies>块中声明的所有依赖项.

Migrating multi-module builds (project aggregation)

Maven的多模块构建与Gradle的多项目构建很好地映射. 尝试相应的教程,以了解如何设置基本的多项目Gradle构建.

要迁移多模块Maven构建,只需执行以下步骤:

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

    例如,以下<modules>块:

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

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

    例子5.声明哪些项目是构建的一部分
    settings.gradle
    rootProject.name = 'simple-multi-module'  // (1)
    
    include 'simple-weather', 'simple-webapp'  // (2)
    settings.gradle.kts
    rootProject.name = "simple-multi-module"  // (1)
    
    include("simple-weather", "simple-webapp")  // (2)
    1. 设置整个项目的名称

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

    gradle projects输出
    > gradle projects
    
    ------------------------------------------------------------
    Root project
    ------------------------------------------------------------
    
    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. 使用跨项目配置复制项目继承.

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

Sharing versions across projects

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

Migrating Maven profiles and properties

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'  // (1)

apply from: "profile-${buildProfile}.gradle"  // (2)

task greeting {
    doLast {
        println message  // (3)
    }
}
profile-default.gradle
ext.message = 'foobar'  // (4)
profile-test.gradle
ext.message = 'testing 1 2 3'  // (4)
profile-prod.gradle
ext.message = 'Hello, world!'  // (4)
build.gradle.kts
val buildProfile: String? by project  // (1)

apply(from = "profile-${buildProfile ?: "default"}.gradle.kts")  // (2)

tasks.register("greeting") {
    val message: String by project.extra
    doLast {
        println(message)  // (3)
    }
}
profile-default.gradle.kts
val message by extra("foobar")  // (4)
profile-test.gradle.kts
val message by extra("testing 1 2 3")  // (4)
profile-prod.gradle.kts
val message by extra("Hello, world!")  // (4)
  1. 检查是否存在(Groovy)或绑定(Kotlin) buildProfile项目属性

  2. 使用脚本文件名中的buildProfile值应用适当的配置文件脚本

  3. 打印出message额外项目属性的值

  4. Initializes the message extra project property, whose value can then be used in the main build script

使用此设置后,您可以通过传递所用项目属性的值(在这种情况下为buildProfile来激活一个配置文件:

gradle greeting输出
> gradle greeting
foobar
Output of gradle -PbuildProfile=test greeting
> gradle -PbuildProfile=test greeting
testing 1 2 3

您不仅限于检查项目属性. 您还可以检查环境变量,JDK版本,运行内部版本的OS或您可以想象的任何其他内容.

要记住的一件事是,高级条件语句使构建更难以理解和维护,类似于它们使面向对象的代码复杂化的方式. 配置文件也是如此. Gradle提供了许多更好的方法来避免广泛使用Maven经常需要的配置文件,例如,通过配置彼此不同的多个任务. 请参阅由Maven Publish插件创建的publish PubName PublicationTo RepoName Repository任务.

有关在Gradle中使用Maven概要文件的冗长讨论,请参阅此博客文章 .

Filtering resources

Maven有一个称为process-resources的阶段,该阶段具有目标resources:resources默认情况下绑定到它的resources:resources . 这为构建作者提供了对各种文件(例如Web资源,打包的属性文件等)执行变量替换的机会.

Gradle的Java插件提供了processResources任务来执行相同的操作. 这是一个复制任务,它将文件从已配置的资源目录(默认为src/main/resources复制到输出目录. 与任何Copy任务一样,您可以对其进行配置以执行文件过滤重命名内容过滤 .

例如,以下配置将源文件视为Groovy SimpleTemplateEngine模板,为这些模板提供了versionbuildNumber属性:

例子7.通过processResources任务过滤资源的内容
build.gradle
processResources {
    expand(version: version, buildNumber: currentBuildNumber)
}
build.gradle.kts
tasks {
    processResources {
        expand("version" to version, "buildNumber" to currentBuildNumber)
    }
}

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

Configuring integration tests

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

如我们在Java和JVM项目中测试章节中所述,此行为很容易在带有源集的Gradle中复制. 然后,您可以使用Task.finalizedBy()将清理任务(例如关闭测试服务器的清理任务)配置为始终在集成测试之后运行,而不管它们是否成功.

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

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

Migrating common plugins

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>
...

Everything outside of the configuration block can safely be ignored when migrating to Gradle. In this case, the corresponding Gradle configuration looks like the following:

例子8.配置Gradle Checkstyle插件
build.gradle
checkstyle {
    config = resources.text.fromFile('checkstyle.xml', 'UTF-8')
    showViolations = true
    ignoreFailures = false
}
build.gradle.kts
checkstyle {
    config = resources.text.fromFile("checkstyle.xml", "UTF-8")
    isShowViolations = true
    isIgnoreFailures = false
}

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

例子9.控制checkstyle任务何时运行
build.gradle
test.mustRunAfter checkstyleMain, checkstyleTest
build.gradle.kts
tasks {
    test {
        mustRunAfter(checkstyleMain, checkstyleTest)
    }
}

如您所见,Gradle配置通常比Maven等效配置短得多. 您还将拥有一个更加灵活的执行模型,因为您不再受Maven固定阶段的约束.

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

Ant goals

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

例子10.调用Ant任务
build.gradle
task sayHello {
    doLast {
        ant.echo message: 'Hello!'
    }
}
build.gradle.kts
tasks.register("sayHello") {
    doLast {
        ant.withGroovyBuilder {
            "echo"("message" to "Hello!")
        }
    }
}

本机还支持Ant属性和文件集. 要了解更多信息,请参阅《 从Gradle中使用Ant》 .

💡

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

Understanding which plugins you don’t need

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

Dealing with uncommon and custom plugins

您可能会遇到在Gradle中没有对应版本的Maven插件,尤其是当您或组织中的某人编写了自定义插件时. 这种情况取决于您了解Gradle(以及可能的Maven)的工作方式,因为您通常必须编写自己的插件.

为了进行迁移,Maven插件有两种主要类型:

  • 那些使用Maven项目对象的对象.

  • 那些没有.

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

如果插件依赖于Maven项目,那么您将不得不重写它. 不要首先考虑Maven插件的工作原理,而要看看它试图解决的问题. 然后尝试解决如何在Gradle中解决该问题. 您可能会发现这两个构建模型之间的差异足以使Maven插件代码"转录"到Gradle插件中才有效. 从好的方面来说,该插件可能比原始的Maven插件更容易编写,因为Gradle具有更丰富的构建模型和API.

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

Further reading

本章涵盖了将Maven构建迁移到Gradle的主要主题. 剩下的就是迁移期间或迁移之后可能有用的其他一些方面:

最后,本指南仅涉及Gradle的一些功能,我们鼓励您从用户手册的其他章节以及教程式的Gradle Guides中了解其余内容.