Introduction to Gradle – Gradle简介

最后修改: 2017年 11月 23日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Gradle is a Groovy-based build management system designed specifically for building Java-based projects.

Gradle是一个基于Groovy的构建管理系统,专门用于构建基于Java的项目。

Installation instructions can be found here.

安装说明可以在这里找到。

2. Building Blocks – Projects and Tasks

2.积木–项目和任务

In Gradle, Builds consist of one or more projects and each project consists of one or more tasks.

在Gradle中,Build由一个或多个项目组成,每个项目由一个或多个任务组成。

A project in Gradle can be assembling a jar, war, or even a zip file.

Gradle中的项目可以是组装一个jarwar,甚至是一个zip文件。

A task is a single piece of work. This can include compiling classes, or creating and publishing Java/web archives.

任务是一项单一的工作。这可以包括编译类,或创建和发布Java/Web档案。

A simple task can be defined as:

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

task hello {
    doLast {
        println 'Baeldung'
    }
}

If we execute the above task using gradle -q hello command from the same location where build.gradle resides, we should see the output in the console.

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

2.1. Tasks

2.1.任务

Gradle’s build scripts are nothing but Groovy:

Gradle的构建脚本只不过是Groovy。

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

We can define tasks that depend on other tasks. Task dependency can be defined by passing the dependsOn: taskName argument in a task definition:

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

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

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

2.2. Adding Behavior to a Task

2.2.为任务添加行为

We can define a task and enhance it with some additional behaviour:

我们可以定义一个任务,并用一些额外的行为来加强它。

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'
    }
}

doFirst and doLast add actions at the top and bottom of the action list, respectively, and can be defined multiple times in a single task.

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

2.3. Adding Task Properties

2.3.添加任务属性

We can also define properties:

我们还可以定义属性。

task ourTask {
    ext.theProperty = "theValue"
}

Here, we’re setting “theValue” as theProperty of the ourTask task.

这里,我们将“theValue”设置为我们的任务的属性。

3. Managing Plugins

3.管理插件

There’re two types of plugins in Gradle – script, and binary.

Gradle中有两种类型的插件–script,binary.

To benefit from additional functionality, every plugin needs to go through two phases: resolving and applying.

为了从附加功能中获益,每个插件都需要经过两个阶段。解决应用

Resolving means finding the correct version of the plugin jar and adding that to the classpath of the project.

解决意味着找到正确版本的插件jar并将其添加到项目的classpath中。

Applying plugins is executing Plugin.apply(T) on the project.

应用插件是在项目上执行Plugin.apply(T)

3.1. Applying Script Plugins

3.1.应用脚本插件

In the aplugin.gradle, we can define a task:

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

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

If we want to apply this plugin to our project build.gradle file, all we need to do is add this line to our build.gradle:

如果我们想把这个插件应用到我们的项目build.gradle文件中,我们所要做的就是在我们的build.gradle中添加这一行。

apply from: 'aplugin.gradle'

Now, executing gradle tasks command should display the fromPlugin task in the task list.

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

3.2. Applying Binary Plugins Using Plugins DSL

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

In the case of adding a core binary plugin, we can add short names or a plugin id:

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

plugins {
    id 'application'
}

Now the run task from application plugin should be available in a project to execute any runnable jar. To apply a community plugin, we have to mention a fully qualified plugin id :

现在,来自application plugin的run任务应该可以在项目中执行任何runnable jar。要应用一个社区插件,我们必须提到一个完全合格的插件ID。

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

Now, Shipkit tasks should be available on gradle tasks list.

现在,Shipkit任务应该可以在gradle tasks列表中找到。

The limitations of the plugins DSL are:

插件DSL的限制是。

  • It doesn’t support Groovy code inside the plugins block
  • plugins block needs to be the top level statement in project’s build scripts (only buildscripts{} block is allowed before it)
  • Plugins DSL cannot be written in scripts plugin, settings.gradle file or in init scripts

Plugins DSL is still incubating. The DSL and other configuration may change in the later Gradle versions.

Plugins DSL仍在孵化中。DSL和其他配置可能会在以后的Gradle版本中发生变化。

3.3. Legacy Procedure for Applying Plugins

3.3.应用插件的传统程序

We can also apply plugins using the “apply plugin”:

我们还可以使用“apply plugin”来应用插件。

apply plugin: 'war'

If we need to add a community plugin, we must add the external jar to the build classpath using the buildscript{} block.

如果我们需要添加一个社区插件,我们必须使用buildscript{}将外部jar添加到构建classpath。块。

Then, we can apply the plugin in the build scripts but only after any existing plugins{} block:

然后,我们可以在构建脚本中应用该插件,但 仅在任何现有的plugins{}之后。block

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

4. Dependency Management

4.依赖性管理

Gradle supports a very flexible dependency management system, it’s compatible with the wide variety of available approaches.

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

Best practices for dependency management in Gradle are versioning, dynamic versioning, resolving version conflicts, and managing transitive dependencies.

Gradle中依赖性管理的最佳实践是版本管理、动态版本管理、解决版本冲突以及管理反式依赖。

4.1. Dependency Configuration

4.1.依赖性配置

Dependencies are grouped into different configurations. A configuration has a name and they can extend each other.

依赖关系被分组为不同的配置。一个配置有一个名称,它们可以相互扩展

If we apply the Java plugin, we’ll have implementation, testImplementation, runtimeOnly configurations available for grouping our dependencies. The default configuration extends “runtimeOnly”.

如果我们应用Java插件,我们将有实施、testImplementation、runtimeOnly配置可用于分组我们的依赖。默认的c配置扩展了”runtimeOnly”。

4.2. Declaring Dependencies

4.2.声明依赖关系

Let’s look at an example of adding some dependencies (Spring and Hibernate) using several different ways:

让我们看一个使用几种不同方式添加一些依赖关系(Spring和Hibernate)的例子。

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

We’re declaring dependencies in various configurations: implementation, testImplementation, and runtimeOnly in various formats.

我们以各种配置来声明依赖关系。implementationtestImplementationruntimeOnly的各种格式。

Sometimes we need dependencies that have multiple artifacts. In such cases, we can add an artifact-only notations @extensionName (or ext in the expanded form) to download the desired artifact:

有时我们需要有多个工件的依赖关系。在这种情况下,我们可以添加一个仅有工件的记号@extensionName (或者扩展后的ext)来下载需要的工件。

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

Here, we added the @jar notation to download only the jar artifact without the dependencies.

在这里,我们添加了@jar符号,只下载jar工件,而不下载依赖项。

To add dependencies to any local files, we can use something like this:

要向任何本地文件添加依赖关系,我们可以使用类似这样的方法。

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

When we want to avoid transitive dependencies, we can do it on the configuration level or on the dependency level:

当我们想避免反式依赖时,我们可以在配置层面或依赖层面上做到这一点

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

5. Multi-Project Builds

5.多项目构建

5.1. Build Lifecycle

5.1.构建生命周期

In the initialization phase, Gradle determines which projects are going to take part in a multi-project build.

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

This is usually mentioned in settings.gradle file, which is located in the project root. Gradle also creates instances of the participating projects.

这通常在settings.gradle文件中提及,该文件位于项目根部。Gradle也会创建参与项目的实例。

In the configuration phase, all created project instances are configured based on Gradle feature configuration on demand.

在配置阶段,所有创建的项目实例都是根据Gradle功能配置按需配置的。

In this feature, only required projects are configured for specific task execution. This way, configuration time is highly reduced for a large multi-project build. This feature is still incubating.

在这个功能中,只有所需的项目被配置为特定的任务执行。这样,对于一个大型的多项目构建来说,配置时间就会大大减少。这个功能仍在孵化中。

Finally, in the execution phase, a subset of tasks, created and configured are executed. We can include code in the settings.gradle and build.gradle files to perceive these three phases.

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

In settings.gradle :

settings.gradle :

println 'At initialization phase.'

In build.gradle :

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. Creating Multi-Project Build

5.2.创建多项目构建

We can execute the gradle init command in the root folder to create a skeleton for both settings.gradle and build.gradle file.

我们可以在根目录下执行gradle init命令,为settings.gradlebuild.gradle文件创建一个骨架。

All common configuration will be kept in the root build script:

所有常用的配置都将保存在根构建脚本中。

allprojects {
    repositories {
        mavenCentral() 
    }
}

subprojects {
    version = '1.0'
}

The setting file needs to include the root project name and subproject name:

设置文件需要包括根项目名称和子项目名称。

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

Now we need to have a couple of subproject folders named greeting-library and greeter to have a demo of a multi-project build. Each subproject needs to have an individual build script to configure its individual dependencies and other necessary configurations.

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

If we’d like to have our greeter project dependent on the greeting-library, we need to include the dependency in the build script of greeter:

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

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

6. Using Gradle Wrapper

6.使用Gradle Wrapper

If a Gradle project has gradlew file for Linux and gradlew.bat file for Windows, we don’t need to install Gradle to build the project.

如果一个Gradle项目有用于Linux的gradlew 文件和用于Windows的gradlew.bat 文件,我们不需要安装Gradle来构建该项目。

If we execute gradlew build in Windows and ./gradlew build in Linux, a Gradle distribution specified in gradlew file will be downloaded automatically.

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

If we’d like to add the Gradle wrapper to our project:

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

gradle wrapper --gradle-version 7.2

The command needs to be executed from the root of the project. This will create all necessary files and folders to tie Gradle wrapper to the project. The other way to do the same is to add the wrapper task to the build script:

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

wrapper {
    gradleVersion = '7.2'
}

Now we need to execute the wrapper task and the task will tie our project to the wrapper. Besides the gradlew files, a wrapper folder is generated inside the gradle folder containing a jar and a properties file.

现在我们需要执行wrapper任务,该任务将把我们的项目与包装器联系起来。除了gradlew文件,在gradle文件夹内还会生成一个wrapper文件夹,其中包含一个jar和一个属性文件。

If we want to switch to a new version of Gradle, we only need to change an entry in gradle-wrapper.properties.

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

7. Conclusion

7.结论

In this article, we had a look at Gradle and saw that it has greater flexibility over other existing build tools in terms of resolving version conflicts and managing transitive dependencies.

在这篇文章中,我们看了一下Gradle,发现它在解决版本冲突和管理横向依赖方面比其他现有的构建工具具有更大的灵活性。

The source code for this article is available over on GitHub.

本文的源代码可在GitHub上获得

Next »

Ant vs Maven vs Gradle