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 and introduces a Groovy-based domain-specific language (DSL) instead of the XML form used by Apache Maven for declaring the project configuration.

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

1.1. Using Gradle Eclipse

为了在 Eclipse 中新建或者打开 Gradle 工程,你需要安装一个叫 Buildship 的工具。安装完成后,你可以通过“File -> New -> Other”创建一个 Gradle 工程,或者通过“File -> Import -> Gradle”打开一个已有的 Gradle 工程。

参考:
Eclipse Buildship: Eclipse Plug-ins for Gradle: https://projects.eclipse.org/projects/tools.buildship
Using the Gradle build system in the Eclipse IDE: http://www.vogella.com/tutorials/EclipseGradle/article.html

1.2. 配置文件

Gradle 包含下面这些配置文件:
(1) build.gradle:指定了一个项目和它的任务。
(2) gradle.properties:用来配置构建属性。
(3) gradle.settings:它对于只有一个项目的构建而言是可选的,如果我们的构建中包含多于一个项目,那么它就是必须的,因为它描述了哪一个项目参与构建。每一个多项目的构建都必须在项目结构的根目录中加入一个设置文件。

1.2.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 文件即可。

1.3. 实例:用 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 基础:Project 和 Task

Gradle 中,有两个基本概念:Project 和 Task。 Project 是指:构建产物(比如 jar 包)或实施产物(将应用程序部署到生产环境),一个 Project 包含一个或多个 Task。Task 是指:不可分的最小工作单元,执行构建工作(比如编译、打包、生成 javadoc、发布等等)。

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

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.1.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.1.2. 任务名的简写

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

gradle d
gradle di
gradle dis
gradle dist

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

gradle compileTest
gradle compTest
gradle cT

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

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

2.1.4. 查询任务列表

通过执行 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: <2017-12-13 Wed>

Creator: Emacs 27.1 (Org mode 9.4)