1. 概述

Gradle 是一个基于 Groovy 的构建管理系统,专门用于构建基于 Java 的项目。具体的安装说明可参考官方文档。

2. 构建基础——项目与任务

在 Gradle 中,构建(Build)由一个或多个项目(Project)组成,而每个项目又由一个或多个任务(Task)组成。

Gradle 中的项目可以组装为 JAR、WAR 甚至是 ZIP 文件。

任务代表具体的工作单元。这可以包括编译类文件,或创建并发布 Java/Web 归档文件。

一个简单的任务可以定义为:

task hello {
    doLast {
        println 'Baeldung'
    }
}

如果我们在 build.gradle 所在的位置使用 gradle -q hello 命令执行上述任务,则应该在控制台中看到输出。

2.1 任务 (Tasks)

Gradle 的构建脚本本质上是 Groovy 代码:

task toLower {
    doLast {
        String someString = 'HELLO FROM BAELDUNG'
        println "Original: " + someString
        println "Lower case: " + someString.toLowerCase()
    }
}

我们可以定义依赖于其他任务的任务。可以通过在任务定义中传递 dependsOn 参数来定义任务依赖项:

task helloGradle {
    doLast {
        println 'Hello Gradle!'
    }
}

task fromBaeldung(dependsOn: helloGradle) {
    doLast {
        println "I'm from Baeldung"
    }
}

2.2 向任务添加行为

我们可以定义任务并通过一些其他行为来增强它:

task helloBaeldung {
    doLast {
        println 'I will be executed second'
    }
}

helloBaeldung.doFirst {
    println 'I will be executed first'
}

helloBaeldung.doLast {
    println 'I will be executed third'
}

helloBaeldung {
    doLast {
        println 'I will be executed fourth'
    }
}

doFirstdoLast 分别在操作列表的顶部和底部添加操作,并且可以在单个任务中多次定义操作。

2.3 添加任务属性

我们还可以定义属性:

task ourTask {
    ext.theProperty = "theValue"
}

在这里,我们将 "theValue" 设置为 ourTask 任务的 theProperty 属性。

3. 管理插件

Gradle 中有两种类型的插件:脚本插件(Script Plugins)和二进制插件(Binary Plugins)。

为了从附加功能中受益,每个插件都需要经历两个阶段:解析(Resolve)和应用(Apply)。

  • 解析意味着找到正确的插件 JAR 版本,并将其添加到项目的类路径中。
  • 应用插件是在项目上执行 Plugin.apply(T)

3.1 应用脚本插件

aplugin.gradle 中,我们可以定义一个任务:

task fromPlugin {
    doLast {
        println "I'm from plugin"
    }
}

如果要将此插件应用于项目的 build.gradle 文件,我们要做的就是将以下行添加到 build.gradle 中:

apply from: 'aplugin.gradle'

现在,执行 gradle tasks 命令应该在任务列表中显示 fromPlugin 任务。

3.2 使用 Plugins DSL 应用二进制插件

在添加核心二进制插件的情况下,我们可以添加短名称或插件 ID:

plugins {
    id 'application'
}

现在,应用程序插件中的 run 任务应该在项目中可用,以执行任何可运行的 JAR。要应用社区插件,我们必须提到一个完全合格的插件 ID:

plugins {
    id "org.shipkit.bintray" version "0.9.116"
}

现在,Shipkit 任务应该在 gradle tasks 列表中可用。

插件 DSL 的局限性是:

  • 它不支持 plugins 块内的 Groovy 代码。
  • plugins 块必须是项目的构建脚本中的顶级语句(在其之前仅允许 buildscript {} 块)。
  • 插件 DSL 不能写在脚本插件、settings.gradle 文件或 init 脚本中。
  • 插件 DSL 仍在发展中。在更高的 Gradle 版本中,DSL 和其他配置可能会更改。

3.3 应用插件的旧方式

我们也可以使用 apply plugin 来应用插件:

apply plugin: 'war'

如果需要添加社区插件,则必须使用 buildscript {} 块将外部 JAR 添加到构建类路径。

然后,我们可以在构建脚本中应用该插件,但是只能在任何现有的 plugins {} 块之后:

buildscript {
    repositories {
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath "org.shipkit:shipkit:0.9.117"
    }
}
apply plugin: "org.shipkit.bintray-release"

4. 依赖管理

Gradle 支持非常灵活的依赖项管理系统,它与多种可用方法兼容。

Gradle 中依赖性管理的最佳实践包括版本控制、动态版本控制、解决版本冲突和管理可传递依赖性。

4.1 依赖配置

依赖性分为不同的配置(Configuration)。配置具有名称,并且它们可以彼此扩展。

如果应用 Java 插件,则将具有可用于对依赖项进行分组的 compiletestCompileruntime 配置。在默认的配置中,runtime 扩展自 compile

4.2 声明依赖项

让我们看一个使用几种不同方式添加一些依赖项(Spring 和 Hibernate)的示例:

dependencies {
    compile group: 'org.springframework', name: 'spring-core', version: '4.3.5.RELEASE'
    compile 'org.springframework:spring-core:4.3.5.RELEASE',
            'org.springframework:spring-aop:4.3.5.RELEASE'
    compile(
        [group: 'org.springframework', name: 'spring-core', version: '4.3.5.RELEASE'],
        [group: 'org.springframework', name: 'spring-aop', version: '4.3.5.RELEASE']
    )
    testCompile('org.hibernate:hibernate-core:5.2.12.Final') {
        transitive = true
    }
    runtime(group: 'org.hibernate', name: 'hibernate-core', version: '5.2.12.Final') {
        transitive = false
    }
}

我们在各种配置中声明依赖项:compiletestCompileruntime,使用了各种格式。

有时我们需要具有多个工件的依赖项。在这种情况下,我们可以添加仅工件的符号 @extensionName(或扩展形式的 ext)来下载所需的工件:

runtime "org.codehaus.groovy:groovy-all:2.4.11@jar"
runtime group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.4.11', ext: 'jar'

在这里,我们添加了 @jar 表示法,以仅下载 JAR 工件,而没有依赖项。

要将依赖项添加到任何本地文件中,我们可以使用如下代码:

compile files('libs/joda-time-2.2.jar', 'libs/junit-4.12.jar')
compile fileTree(dir: 'libs', include: '*.jar')

当我们想要避免传递依赖时,可以在配置级别或依赖级别上进行:

configurations {
    testCompile.exclude module: 'junit'
}

testCompile("org.springframework.batch:spring-batch-test:3.0.7.RELEASE"){
    exclude module: 'junit'
}

5. 多项目构建

5.1 构建生命周期

在初始化阶段,Gradle 确定哪些项目将参与多项目构建。

通常在位于项目根目录中的 settings.gradle 文件中提到此问题。Gradle 还会创建参与项目的实例。

在配置阶段,将根据需要根据 Gradle 功能配置来配置所有创建的项目实例。

在此功能中,仅将必需的项目配置为用于特定任务执行。这样,可以大大减少大型多项目构建的配置时间。此功能仍在发展中。

最后,在执行阶段,将执行创建和配置的任务子集。我们可以在 settings.gradlebuild.gradle 文件中包含代码以感知这三个阶段。

settings.gradle 中:

println 'At initialization phase.'

build.gradle 中:

println 'At configuration phase.'

task configured { println 'Also at the configuration phase.' }

task execFirstTest { doLast { println 'During the execution phase.' } }

task execSecondTest {
    doFirst { println 'At first during the execution phase.' }
    doLast { println 'At last during the execution phase.' }
    println 'At configuration phase.'
}

5.2 创建多项目构建

我们可以在根文件夹中执行 gradle init 命令来为 settings.gradlebuild.gradle 文件创建框架。

所有通用配置将保留在根构建脚本中:

allprojects {
    repositories {
        mavenCentral() 
    }
}

subprojects {
    version = '1.0'
}

设置文件需要包含根项目名称和子项目名称:

rootProject.name = 'multi-project-builds'
include 'greeting-library','greeter'

现在,我们需要有几个子文件夹,分别名为 greeting-librarygreeter,以演示多项目构建。每个子项目都需要有一个单独的构建脚本来配置它们各自的依赖关系和其他必要的配置。

如果我们想让 greeter 项目依赖于 greeting-library,我们需要在 greeter 的构建脚本中包含依赖项:

dependencies {
    compile project(':greeting-library') 
}

6. 使用 Gradle 包装器

如果 Gradle 项目具有针对 Linux 的 gradlew 文件和针对 Windows 的 gradlew.bat 文件,那么我们无需安装 Gradle 即可构建该项目。

如果我们在 Windows 中执行 gradlew build,而在 Linux 中执行 ./gradlew build,则 gradlew 文件中指定的 Gradle 发行版将自动下载。

如果我们想将 Gradle 包装器添加到我们的项目中:

gradle wrapper --gradle-version 4.2.1

该命令需要从项目的根目录执行。这将创建所有必要的文件和文件夹,以将 Gradle 包装器绑定到项目。另一种方法是将包装器任务添加到构建脚本中:

task wrapper(type: Wrapper) {
    gradleVersion = '4.2.1'
}

现在,我们需要执行包装器任务,该任务会将我们的项目绑定到包装器。除了 gradlew 文件之外,在 gradle 文件夹内还会生成一个 wrapper 文件夹,其中包含一个 JAR 和一个属性文件。

如果我们想切换到 Gradle 的新版本中,我们只需要更改 gradle-wrapper.properties 中的条目。

7. 结论

在本文中,我们对 Gradle 进行了研究,发现在解决版本冲突和管理传递依赖方面,它比其他现有的构建工具具有更大的灵活性。


说明: 本文内容基于较早期的 Gradle 版本(如 4.x)。请注意,自 Gradle 7.0 起,compiletestCompileruntime 等配置已被废弃或移除,建议在新项目中改用 implementationtestImplementation 等新配置。此外,文中提到的 Bintray 仓库服务已停止运营,相关插件示例可能无法直接使用。