Gradle

Table of Contents

1. Gradle 简介

Gradle is an open source build automation system that builds upon the concepts of Apache Ant and Apache Maven.

Gradle 不使用 XML 文件(Ant/Maven 均使用 XML 文件)来声明项目的配置,而是使用 domain-specific language (DSL),目前 Gradle 支持两种 DSL:

  1. Groovy DSL
  2. Kotlin DSL

参考:
Gradle Website: https://gradle.org/
Gradle User Guide: https://docs.gradle.org/current/userguide/userguide.html

1.1. Gradle 项目的目录结构

Gradle 项目的目录结构如下:

├── .gradle                     (1)
│   ├── 4.8                     (2)
│   ├── 4.9                     (2)
│   └── ⋮
├── build                       (3)
├── gradle
│   └── wrapper                 (4)
├── gradle.properties           (5)
├── gradlew                     (6)
├── gradlew.bat                 (6)
├── settings.gradle.kts         (7)
├── subproject-one              (8)
|   └── build.gradle.kts        (9)
├── subproject-two              (8)
|   └── build.gradle.kts        (9)
└── ⋮

相关文件的说明如下:
(1) Project-specific cache directory generated by Gradle.
(2) Version-specific caches (e.g., to support incremental builds).
(3) The build directory of this project into which Gradle generates all build artifacts.
(4) Contains the JAR file and configuration of the Gradle Wrapper.
(5) Project-specific Gradle configuration properties.
(6) Scripts for executing builds using the Gradle Wrapper.
(7) The project’s settings file where the list of subprojects is defined.
(8) Usually, a project is organized into one or multiple subprojects.
(9) Each subproject has its own Gradle build script.

参考:https://docs.gradle.org/current/userguide/directory_layout.html#dir:project_root

1.1.1. 设置 proxy

如果想对所有的 gradle 项目设置代理,可以在 GRADLE_USER_HOME(为目录 “~/.gradle/”)下新建文件 gradle.properties,增加配置项:

systemProp.http.proxyHost=127.0.0.1
systemProp.http.proxyPort=10384
systemProp.https.proxyHost=127.0.0.1
systemProp.https.proxyPort=10384

如果只是对单个项目设置代理,则仅修改项目根目录中的 gradle.properties 文件即可。

参考:https://docs.gradle.org/current/userguide/networking.html

1.2. 实例:用 Gradle 编译 Java 程序

下面以一个简单的 Hello world 工程(你也可以使用命令 gradle init --type java-application 来自动生成 Hello world 工程)来介绍 Gradle 的基本使用。

这里假定你的工程源码已经存在(需要符合 Maven 的规范,也就是不同资源分别放在约定目录 src/main/java, src/main/resources, src/test/java and src/test/resources 等中),其目录结构和内容如下:

$ find /home/cig01/java-demo
/home/cig01/java-demo
/home/cig01/java-demo/src
/home/cig01/java-demo/src/main
/home/cig01/java-demo/src/main/java
/home/cig01/java-demo/src/main/java/App.java
$ cat ./src/main/java/App.java
public class App {

    public static void main(String[] args) {
        System.out.println("Hello world");
    }
}

首先,在当前目录中新建文件 build.gradle ,其内容为:

apply plugin: 'java'

然后,执行 gradle build 命令即可开始编译。如:

$ gradle build
:compileJava
:processResources NO-SOURCE
:classes
:jar
:assemble
:compileTestJava NO-SOURCE
:processTestResources NO-SOURCE
:testClasses UP-TO-DATE
:test NO-SOURCE
:check UP-TO-DATE
:build

BUILD SUCCESSFUL

Total time: 1.962 secs

编译完成后,会生成 jar 包“build/libs/java-demo.jar”(包的名字 java-demo 默认为当前目录名字)。测试运行如下:

$ java -cp build/libs/java-demo.jar App
Hello world

说明:使用命令 gradle run 可更方便地执行编译后的程序。不过要求我们使用插件 application,且配置 mainClassName 为主程序类名。即把文件 build.gradle 修改为:

apply plugin: 'java'
apply plugin: 'application'

mainClassName = 'App'

这时,运行 gradle run 可执行程序 App。

$ gradle run
:compileJava UP-TO-DATE
:processResources NO-SOURCE
:classes UP-TO-DATE
:run
Hello world

BUILD SUCCESSFUL

Total time: 1.846 secs

上面的输出中有很多是 gradle 的输出,查找程序 App 的输出(字符串“Hello world”)不方便。可以使用 -q 选项来禁止 gradle 输出,这样可更快捷地查看到程序 App 的输出。如:

$ gradle -q run
Hello world

参考:https://guides.gradle.org/building-java-applications/

2. Gradle 基础

2.1. 构建的三个阶段(初始化/配置/执行)

Gradle 的构建过程可以分为下面三个阶段:

  1. Initialization
    • Detects the settings.gradle(.kts) file.
    • Creates a Settings instance.
    • Evaluates the settings file to determine which projects (and included builds) make up the build.
    • Creates a Project instance for every project.
  2. Configuration
    • Evaluates the build scripts, build.gradle(.kts), of every project participating in the build.
    • Creates a task graph for requested tasks.
  3. Execution
    • Schedules and executes the selected tasks.
    • Dependencies between tasks determine execution order.
    • Execution of tasks can occur in parallel.

参考:https://docs.gradle.org/current/userguide/build_lifecycle.html#sec:build_phases

2.4. Task 介绍(gradle 命令行基本用法)

Gradle 中,Task 是不可分的最小工作单元,用于执行构建工作(比如编译、打包、生成 javadoc、发布等等)。

gradle 的命令行用法为: gradle [option...] [task...] 。比如 gradle compile test 就是执行任务 compile 和 test。

任务之间可以有依赖。比如下面的 build.gradle 文件中定义了如图 1 所示的任务依赖关系。

task compile {
    doLast {
        println 'compiling source'
    }
}

task compileTest(dependsOn: compile) {           //这里设置了任务compileTest依赖于任务compile
    doLast {
        println 'compiling unit tests'
    }
}

task test(dependsOn: [compile, compileTest]) {    //这里设置了任务test依赖于任务compile和compileTest
    doLast {
        println 'running unit tests'
    }
}

task dist(dependsOn: [compile, test]) {           //这里设置了任务dist依赖于任务compile和test
    doLast {
        println 'building the distribution'
    }
}

gradle_tasks_exam.png

Figure 1: Task dependencies

任务之间有依赖于,先执行依赖。比如执行命令 gradle dist test 时,会依次执行任务 compile,compileTest,test,dist(每个任务最多会执行一次)。测试如下:

$ gradle dist test
:compile
compiling source
:compileTest
compiling unit tests
:test
running unit tests
:dist
building the distribution

BUILD SUCCESSFUL

Total time: 1 secs

每个任务最多执行一次。gradle test testgradle test 是相同的。

参考:https://docs.gradle.org/current/userguide/tutorial_gradle_command_line.html

2.4.1. 排除某个任务的执行(-x)

使用选项 -x 可以排除某个任务的执行。以图 1 中的任务为例, gradle dist -x test 会排除任务 test(及 test 的依赖)的执行:

$ gradle dist -x test
:compile
compiling source
:dist
building the distribution

BUILD SUCCESSFUL

Total time: 1 secs

2.4.2. 任务名的简写

只要不冲突,任务名可以简写。如下面 4 种用法效果相同:

gradle d
gradle di
gradle dis
gradle dist

此外,如果任务名是 Camel case 形式,只要不冲突,对单词也可以进行简写。如下面 3 种用法效果相同:

gradle compileTest
gradle compTest
gradle cT

2.4.3. 强制重新执行任务(--rerun-tasks)

默认 gradle 是增量编译的,如果任务的输入文件没有修改就不会重新编译。可以通过指定选项 --rerun-tasks 来使 gradle 总是执行指定任务。

2.4.4. 查询任务列表(gradle tasks)

通过执行 gradle tasks 可以查询当前项目中所有的任务。

3. Gradle 插件简介

Gradle 的核心能做的事件非常少,所有有用特性(比如编译 Java 代码等)都由 Gradle 插件来提供。

一个 Gradle 插件能够:
(1) 在 Project 中添加新 Task;
(2) 为新加入的任务提供默认配置(如约定源文件默认位置);
(3) 加入新的属性;
(4) 为项目加入新的依赖。

对于简单的任务,你不用自己编写插件,Gradle 提供了一些 Standard plugins ,下面是它们的不完整列表:

Table 1: 部分的 Gradle standard plguins
Plugin Id Automatically applies Works with Description
java java-base - Adds Java compilation, testing and bundling capabilities to a project.
groovy java, groovy-base - Adds support for building Groovy projects.
scala java, scala-base - Adds support for building Scala projects.
antlr java - Adds support for generating parsers using Antlr.
application java, distribution - Adds tasks for running and bundling a Java project as a command-line application.
ear - java Adds support for building J2EE applications.
jetty war - Deploys your web application to a Jetty web container embedded in the build.
osgi java-base java Adds support for building OSGi bundles.
war java - Adds support for assembling web application WAR files.

要使用插件(假设插件名为 foo),在文件 build.gradle 中使用 apply plugin: 'foo' 即可。

参考:
https://docs.gradle.org/current/userguide/plugins.html

3.1. 插件 JavaPlugin(java)简介

JavaPlugin 是 Gradle 中非常基础的一个插件,在文件 build.gradle 中增加下面内容即可使用它。

apply plugin: 'java'
// apply plugin: org.gradle.api.plugins.JavaPlugin   // 和上一行相同
// apply plugin: JavaPlugin                          // 和上一行相同

JavaPlugin 增加了下面 Tasks 到你的工程中。

Table 2: JavaPlugin 往你的工程中增加了下面 Tasks
Task name Depends on Type Description
compileJava All tasks which produce the compile classpath. This includes the jar task for project dependencies included in the compile configuration. JavaCompile Compiles production Java source files using javac.
processResources - Copy Copies production resources into the production resources directory.
classes The compileJava task and the processResources task. Some plugins add additional compilation tasks. Task Assembles the production classes and resources directories.
compileTestJava compile, plus all tasks which produce the test compile classpath. JavaCompile Compiles test Java source files using javac.
processTestResources - Copy Copies test resources into the test resources directory.
testClasses compileTestJava task and processTestResources task. Some plugins add additional test compilation tasks. Task Assembles the test classes and resources directories.
jar compile Jar Assembles the JAR file
javadoc compile Javadoc Generates API documentation for the production Java source, using Javadoc
test compile, compileTest, plus all tasks which produce the test runtime classpath. Test Runs the unit tests using JUnit or TestNG.
uploadArchives The tasks which produce the artifacts in the archives configuration, including jar. Upload Uploads artifacts in the archives configuration, including the JAR file.
clean - Delete Deletes the project build directory.
cleanTaskName - Delete Deletes files created by specified task. cleanJar will delete the JAR file created by the jar task, and cleanTest will delete the test results created by the test task.

JavaPlugin 默认使用下面的工程结构:

Table 3: JavaPlugin 默认使用的工程结构
Directory Meaning
src/main/java Production Java source
src/main/resources Production resources
src/test/java Test Java source
src/test/resources Test resources
src/sourceSet/java Java source for the given source set
src/sourceSet/resources Resources for the given source set

参考:https://docs.gradle.org/current/userguide/java_plugin.html

3.1.1. 实例:修改工程默认结构

如果你的 java 源码在“scr/java”中,而不是默认的“src/main/java”中,你可以在文件 build.gradle 增加下面配置:

sourceSets {
    main {
        java {
            srcDirs = ['src/java']
        }
    }
}

4. Dependency Management

Maven repository 中的库都可以引入到 Gradle 中。在项目的 build.gradle 文件中配置即可。下面是一个简单例子:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
    testCompile group: 'junit', name: 'junit', version: '4.+'
}

参考:https://docs.gradle.org/current/userguide/artifact_dependencies_tutorial.html

5. Tips

5.1. 指定 Java 环境

如果编译项目时要显式地指定 Java 环境,可以采用下面任一种方法。

方法 1、在 gradle.properties 中指定:

org.gradle.java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home

方法 2、在运行时指定:

./gradlew build -Dorg.gradle.java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home

参考:https://stackoverflow.com/questions/18487406/how-do-i-tell-gradle-to-use-specific-jdk-version

Author: cig01

Created: <2016-06-13 Mon>

Last updated: <2024-09-13 Fri>

Creator: Emacs 27.1 (Org mode 9.4)