07_project_02_gradle

第六十四章 Gradle

1 简介

Gradle是一个开源的、通用型自动构建系统。Gradle可用于构建Java项目、C++项目、前端开发项目,移动应用项目等不同种类、不同编程语言的项目。Gradle并未采用XML语言;它使用了Apache Groovy或者Kotlin语言来描述和定义项目构建的过程,给予了开发人员极大的灵活性。当运行Gradle时,Gradle会在内部构建一个有向无环图(Directed Acyclic Graph)来确定项目构建的步骤和先后顺序。Gradle同时支持Apache MavenApache Ivy的仓库(Repository),并支持代码库的依赖管理。Gradle会自动分析构建过程;每次运行时,Gradle仅运行那些需要再次运行的任务,从而提高运行效率。因为Gradle的众多特性,越来越多的厂商和项目采用Gradle自动构建系统。

1.1 Gradle的优势

  1. 性能优势。为了提高自动构建的运行速度,Gradle设计了许多增强特性以提升性能。例如:Gradle支持增量构建(Incremental Build)。如果在上一次构建之后,一个任务所读取的文件没有发生变化的话,Gradle会认为该任务已处于最新状态,无需反复执行。Gradle支持共享构建(Shared Build Cache),如果一个任务已在另一台服务器上执行的话,本地构建会从共享构建缓存中获取该任务的结果。因此,本地构建无需再次执行这项任务。Gradle支持并行化构建(Parallel Execution)和并行化依赖下载(Parallel Dependency Download)。
  2. 跟踪与展示。Gradle支持基于Web的可视化的构建过程展示(Web-based Build Visualization)。Gradle还支持构建过程的比较(Build Comparison),突出显示多个构建之间的不同之处。开发人员还能跟踪和查看构建的各项指标。
  3. Gradle支持多种运行方式。例如:Gradle支持持续构建(Continuous Build);Gradle一旦检测到有新的更新,就会触发一次构建。Gradle支持执行单项任务(Execute a Specific Task)。Gradle支持查看哪些任务会被执行(Dry Run)。开发人员能够选择当遇到错误时是否继续运行构建。
  4. Gradle支持使用Groovy或者Kotlin来定义和描述构建过程。这个构建过程的描述代码也是可以测试的(Testable)。
  5. Gradle非常灵活、可扩展性好。开发人员可以为其具体的运行环境或者工程做个性化的设置(Customization)。

1.2 Gradle VS. Apache Maven

Gradle和Apache Maven都是通用型构建系统。与Apache Maven相比,Gradle有哪些优势呢?

  1. Gradle具备更好的灵活性和可扩展性。Apache Maven使用XML语言来描述项目构建过程;配置XML往往是一项乏味无趣,而且容易出错的任务。Gradle改善了这一点;它采用了Groovy或者Kotlin来描述构建过程。Groovy/Kotlin的代码具有可读性好,易于测试,可扩展性好等优点。
  2. Gradle比Apache Maven运行速度更快。根据Gradle官方网站提供的数据,Gradle比Apache Maven至少快一倍。
  3. 自从Gradle支持Kotlin语言描述构建过程之后,Gradle具有更好的IDE集成开发环境用户体验。
  4. Apache Maven和Gradle都能自动处理代码库之间的依赖关系。Apache Maven通过版本号来解决依赖关系,而Gradle则提供了更加丰富的依赖规则。

在接下来的内容中,我们将着重介绍如何使用Gradle工具构建Java工程。下面的内容将使用Groovy语言。在阅读时,读者无需事先掌握任何Groovy语言的知识,也能完整的理解全部内容。

2 Gradle基础知识

2.1 任务(Task)

Gradle可以同时管理一个或者多个工程(Projects)。每个工程是由一个或者多个任务(Task)组成的。在一个任务中,开发人员可以完成一项工作,例如:编译源代码、运行测试、打包、或者生成文档等。

使用Groovy语言定义一个任务是一件容易的事情。如下面的例子所示,该例定义了一个名为HelloLittleWaterdrop的任务。在运行时,该任务会打印字符串"Hello Little Waterdrop"。从语法结构来看,一个任务的定义由关键字task开始,随后紧跟着任务名称(HelloLittleWaterdrop)。任务的主体部分包含在一对花括号之间。

一个任务(Task)可以包含一个或者多个动作(Action)。当执行一个任务时,Gradle会依次执行该任务包含的所有动作(Actions)。在这个例子中,doLast是一个预定义的名称;它不仅定义了一个动作(该动作的内容在随后的一对花括号中定义),而且,该动作被添加在任务的动作队列(Action List)尾部。doFirst是另一个预定义的名称,使用方法与doLast类似。只不过,doFirst会将动作添加至任务的动作列表头部。

// 文件 build.gradle
task HelloLittleWaterdrop {
	doLast {
		println 'Hello Little Waterdrop'
	}
}

我们可以使用如下命令执行一个任务。

> gradle -q HelloLittleWaterdrop
Hello Little Waterdrop

doLast和doFirst可以多次使用。Gradle会按照它们出现的顺序依次将动作添加至队尾或者队头。然后再按照任务队列中的顺序依次执行所有任务。

// 文件 build.gradle
task HelloLittleWaterdrop {
	doFirst {
		println 'Step 2: Print Hello Little Waterdrop'
	}
	doFirst {
		println 'Step 1: Prepare to print Hello Little Waterdrop'
	}
	doLast {
		println 'Step 3: Hello Little Waterdrop had been printed'
	}
	doLast {
		println 'Step 4: Congraduations'
	}
}

执行结果为:

> gradle -q HelloLittleWaterdrop
Step 1: Prepare to print Hello Little Waterdrop
Step 2: Print Hello Little Waterdrop
Step 3: Hello Little Waterdrop had been printed
Step 4: Congraduations

2.2 项目(Project)

一个项目(Project)是对一个项目构建过程的描述。每一个项目都有一个build.gradle文件。在构建一个项目时,Gradle会根据该项目的build.gradle文件的内容依次运行任务,完成构建过程。因为每一个项目都有着一个对应的build.gradle文件,因此,在构建一个多项目工程的过程中,Gradle会读取和运行多个build.gradle文件。

settings.gradle是Gradle构建过程中的配置文件,它描述着构建过程中的一些Gradle的行为。settings.gradle是可选的;当settings.gradle不存在时,Gradle会采用默认的行为方式生成一个settings.gradle。在每一次构建过程中,Gradle只会读取一个settings.gradle文件(无论是单工程构建或者多工程构建)。我们在第四节介绍多工程构建时,会再次讨论settings.gradle。

Gradle的项目构建过程大致可分为以下四个步骤:

  1. 以默认行为方式生成一个配置对象(Settings对象)。
  2. 如果settings.gradle存在,则读取其内容并修改配置对象(Settings对象),覆盖其默认的行为方式。
  3. 根据配置对象(Settings对象),生成工程之间的结构关系(Create the hierarchy of projects)。
  4. 依次执行每个工程的build.gradle文件的内容。在默认方式下,Gradle采用广度优先的顺序(breadth-wise order)依次构建项目。

2.3 插件(Plugins)

一个插件(Plugins)是一组任务(Tasks)的集合。使用插件的目的是为了提供更加丰富的构建方法,扩展Gradle的基本功能。在工程中使用插件能帮助开发人员更加快速、方便的搭建项目的构建过程,使用统一的配置方式,遵循业界流行的构建方法。

一般来讲,插件包含的任务是紧密相关的。例如:Gradle的Java插件(The Java Plugin)包含了Java语言的编译、测试和打包等任务。使用Java插件,开发人员能够快速的构建、测试和部署Java项目。

2.4 任务依赖(Task Dependency)

最后,我们再来讨论一些任务(Task)的重要属性。开发人员可以为任务(Task)添加描述信息。例如:下面的示例为HelloLittleWaterdrop任务添加了描述信息"This is an example of Task definition"。

// 文件 build.gradle
task HelloLittleWaterdrop {
	description 'This is an example of Task definition'
	doLast {
		println 'Hello Little Waterdrop'
	}
}

执行结果为:

> gradle -q HelloLittleWaterdrop
Hello Little Waterdrop

在定义任务内容的同时,还可以同时指定任务的依赖关系。例如:下面的示例中定义了两个任务HelloLittleWaterdrop和ByeLittleWaterdrop。任务ByeLittleWaterdrop需要在任务HelloLittleWaterdrop执行完毕后再执行。当在任务中使用dependsOn属性后,开发人员可以直接使用任务名称来指定所依赖的任务。当本任务(Task)依赖于另一个项目(Project)中的任务(Task)时,则可用":ProjectName:TaskName"的方式来指定任务。我们称这种任务指定的方式为任务定位(Task Locating)。在完成任务依赖的介绍之后,我们会介绍任务定位的几种方式。

// 文件 build.gradle
task HelloLittleWaterdrop {
	doLast {
		println 'Hello Little Waterdrop'
	}
}

task ByeLittleWaterdrop {
	dependsOn 'HelloLittleWaterdrop'
	doLast {
		println 'Bye Little Waterdrop'
	}
}

执行结果为:

> gradle -q ByeLittleWaterdrop
Hello Little Waterdrop
Bye Little Waterdrop

任务定位方法一:在开发build.gradle时,开发人员常常需要定位任务(Task)。在相同的build.gradle文件中,可以使用任务的名字定位该任务,或者使用项目的名称来指定哪个项目中的任务。

// 文件 build.gradle
task HelloLittleWaterdrop {
	doLast {
		println 'Hello Little Waterdrop'
	}
}

println HelloLittleWaterdrop.name
println project.HelloLittleWaterdrop.name

执行结果为:

> gradle -q HelloLittleWaterdrop
HelloLittleWaterdrop
HelloLittleWaterdrop
Hello Little Waterdrop

任务定位方法二:在Gradle运行时,Gradle会创建一个任务集合(Task Collection) tasks。所以,在build.gradle文件中可以通过tasks变量来定位任务。

// 文件 build.gradle
task HelloLittleWaterdrop {
	doLast {
		println 'Hello Little Waterdrop'
	}
}

println tasks.HelloLittleWaterdrop.name
println tasks.named('HelloLittleWaterdrop').get().name

执行结果为:

> gradle -q HelloLittleWaterdrop
HelloLittleWaterdrop
HelloLittleWaterdrop
Hello Little Waterdrop

第三种任务定位的方法是使用任务的路径(Task's Path)。我们在指定任务依赖(Task Dependency)时使用过。在下面的例子中,getByPath()函数接收一个任务路径,并返回该任务对象。任务路径的结构和文件系统(File System)的文件路径(File Path)非常相似;任务路径以冒号(:)分隔项目(Project)和任务(Task)。以冒号开始的任务路径为绝对任务路径(Absolute Task Path);其他的路径为相对任务路径(Relative Task Path)。

// 文件 build.gradle
task HelloLittleWaterdrop {
	doLast {
		println 'Hello Little Waterdrop'
	}
}

println tasks.getByPath('HelloLittleWaterdrop').name
println tasks.getByPath(':HelloLittleWaterdrop').name
println tasks.getByPath('project:HelloLittleWaterdrop').name
println tasks.getByPath(':project:HelloLittleWaterdrop').name

Gradle的任务(Task)还可以传递参数。在一些场景下,开发人员可能需要向任务传递参数。那么,在这种情况下,开发人员可以定义一个新的任务类,并通过其构造函数来接收参数,并创建任务实例。例如:在下面的例子中定义了一个新的任务类PrintMessageTask,用于打印输出消息。该消息的内容由构造函数的参数确定。在该例中,PrintMessageTask继承自Gradle提供的DefaultTask类。其中,@Inject(@javax.inject.Inject)标注了新任务类的构造函数;@TaskAction(@org.gradle.api.tasks.TaskAction)标注了新任务类中的动作(Action)。

class PrintMessageTask extends DefaultTask {
	final String message

	@Inject
	PrintMessageTask(String message) {
		this.message = message
	}

	@TaskAction
	def print() {
		println this.message
	}
}

tasks.create('HelloLittleWaterdrop', PrintMessageTask, 'Hello Little Waterdrop')

3 Gradle工程(Gradle Project)

在了解了Gradle的基本概念之后,接下来,我们将会创建并运行一个Java工程,并使用Gradle来完成这个工程的构建过程。在本章中,我们将以创建Java应用程序(Java Application)为例,若对其他编程语言或者其他类型的工程感兴趣的读者可参考Gradle init文档

3.1 创建新工程

Gradle init命令(更准确的说是Gradle init plugin)主要用来创建一个新的工程。当开发人员在一个空的工程目录下执行gradle init之后,Gradle会引导开发人员完成一个新工程的创建,如下所示。在创建过程中,Gradle会询问:1. 创建的工程类型(回答:应用程序Application);2. 编程语言(回答:Java);3. 使用Groovy或者Kotlin脚本描述工程构建过程(回答:Groovy);4. 选择测试框架(回答:JUnit 4);5. 工程名称(回答:FirstJavaProject);6. 源代码的包名(回答:com.littlewaterdrop)。

> mkdir FirstJavaProject
> cd FirstJavaProject/
> gradle init
Select type of project to generate:
  1: basic
  2: application
  3: library
  4: Gradle plugin
Enter selection (default: basic) [1..4] 2

Select implementation language:
  1: C++
  2: Groovy
  3: Java
  4: Kotlin
  5: Swift
Enter selection (default: Java) [1..5] 3

Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 1

Select test framework:
  1: JUnit 4
  2: TestNG
  3: Spock
  4: JUnit Jupiter
Enter selection (default: JUnit 4) [1..4] 1

Project name (default: project): FirstJavaProject
Source package (default: FirstJavaProject): com.littlewaterdrop

> Task :init
Get more help with your project: https://docs.gradle.org/6.6.1/userguide/tutorial_java_projects.html

BUILD SUCCESSFUL in 1m 8s
2 actionable tasks: 2 executed

3.2 工程结构

在新创建的工程目录下,Gradle init生成了一些初始文件;它们可分为以下几类。

  1. build.gradle是描述工程构建过程的脚本文件,以Groovy语言实现。
  2. settings.gradle是用于设置Gradle的行为和工程之间关系的配置文件。
  3. gradlew和gradlew.bat是两个脚本文件,分别适用于Linux环境和Windows环境。开发人员可以使用它们构建此工程。
  4. gradle目录下存放的是Gradle Wrapper文件。Gradle Wrapper文件是真正运行和构建工程的程序。它能帮助开发人员正确的构造工程(即使当前服务器并未安装工程指定的Gradle版本)。
  5. src目录下存放的是Java源代码文件。

src目录下有main和test两个目录。main目录存放的是工程的源代码文件;而test目录下存放的是工程的测试源代码文件。这些文件用于测试src/main下的源代码的功能。App.java和AppTest.java放在com.littlewaterdrop的包目录下,这正对应着在运行gradle init时输入的包名称com.littlewaterdrop。

在main和test目录下分别有resources目录,可以存放工程配置文件(例如:日志配置文件,或者工程的配置文件)。

FirstJavaProject
 |- build.gradle
 |- settings.gradle
 |- gradlew
 |- gradlew.bat
 |- gradle
 |  |- wrapper
 |  |  |- gradle-wrapper.jar
 |  |  |- gradle-wrapper.properties
 |- src
 |  |- main
 |  |  |- java
 |  |  |  |- com
 |  |  |  |  |- littlewaterdrop
 |  |  |  |  |  |- App.java
 |  |  |- resources
 |  |- test
 |  |  |- java
 |  |  |  |- com
 |  |  |  |  |- littlewaterdrop
 |  |  |  |  |  |- AppTest.java
 |  |  |- resources

3.3 工程构建脚本文件gradle.build

在初始创建的版本中,gradle.build文件包含了一些最基本的工程构建信息。

  1. 首先,在插件属性中,该脚本使用了Java插件application插件。插件application会告诉Gradle使用Distribution插件。Java插件提供了Java语言的构建、测试和打包的功能;Distribution插件提供了工程分发功能(Project Distribution)。
  2. 然后,在repositories属性中。在工程构建过程中,Gradle会从repositories中寻找并下载第三方的依赖库。常见的公开库有Maven CentralBintray JCenterGoogle Android。在本例中,我们使用了Bintray JCenter。在实际应用中,开发人员可以根据自身情况选择使用。
  3. 我们还添加了依赖库dependencies。implementation和testImplementation是两个依赖关系的配置对象(Dependency Configuration)。简单来说,在工程编译的过程(Project Build)中,该工程依赖于com.google.guava:guava:29.0-jre包。在工程的测试过程中,该工程依赖于junit:junit:4.13包。包名遵守groupId:artifictId:version格式,与Apache Maven包名格式相同。
  4. 最后,我们指定该应用程序的主类(main class)为com.littlewaterdrop.App。
/*
 * This file was generated by the Gradle 'init' task.
 *
 * This generated file contains a sample Java project to get you started.
 * For more details take a look at the Java Quickstart chapter in the Gradle
 * User Manual available at https://docs.gradle.org/6.6.1/userguide/tutorial_java_projects.html
 */

plugins {
    // Apply the java plugin to add support for Java
    id 'java'

    // Apply the application plugin to add support for building a CLI application.
    id 'application'
}

repositories {
    // Use jcenter for resolving dependencies.
    // You can declare any Maven/Ivy/file repository here.
    jcenter() 
	// mavenCentral() // 当开发人员选择使用Maven Central库时
	// google()       // 当开发人员选择使用Google Android库时
	// maven {        // 当开发人员选择使用内部Maven库时
    //     url "https://maven.littlewaterdrop.com/internal/release"
    // }
}

dependencies {
    // This dependency is used by the application.
    implementation 'com.google.guava:guava:29.0-jre'

    // Use JUnit test framework
    testImplementation 'junit:junit:4.13'
}

application {
    // Define the main class for the application.
    mainClassName = 'com.littlewaterdrop.App'
}

3.4 工程构建的输出

在工程初始化后,App.java和AppTest.java的内容如下:

/*
 * This Java source file was generated by the Gradle 'init' task.
 */
package com.littlewaterdrop;

public class App {
    public String getGreeting() {
        return "Hello world.";
    }

    public static void main(String[] args) {
        System.out.println(new App().getGreeting());
    }
}
/*
 * This Java source file was generated by the Gradle 'init' task.
 */
package com.littlewaterdrop;

import org.junit.Test;
import static org.junit.Assert.*;

public class AppTest {
    @Test public void testAppHasAGreeting() {
        App classUnderTest = new App();
        assertNotNull("app should have a greeting", classUnderTest.getGreeting());
    }
}

当我们准备构建该工程时,我们可以使用如下命令查询该工程的任务(Task)列表。注意,此时我们执行的是工程根目录下的gradlew命令,而不是gradle构建工具的gradle命令。因为列表很长,我们仅展示了前面的几行信息。

> ./gradlew task --all

> Task :tasks

------------------------------------------------------------
Tasks runnable from root project
------------------------------------------------------------

Application tasks
-----------------
run - Runs this project as a JVM application

Build tasks
-----------
assemble - Assembles the outputs of this project.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
classes - Assembles main classes.
clean - Deletes the build directory.
jar - Assembles a jar archive containing the main classes.
testClasses - Assembles test classes.
...

构建该工程可运行./gradlew build。

> ./gradlew build

BUILD SUCCESSFUL in 2s
7 actionable tasks: 7 executed

构建完毕后,工程的输出文件在build目录下,如下所示。在build目录下,会出现"classes"、"distributions"、"generated"、"libs"、"reports"、"scripts"、"test-results"和"tmp"目录。其中,classes目录包含的是java源代码编译出的.class文件;distributions目录下存放的是.jar文件,用于发布该工程。

FirstJavaProject
 |- build
 |  |- classes
 |  |- distributions
 |  |- generated
 |  |- libs
 |  |- reports
 |  |- scripts
 |  |- test-results
 |  |- tmp
 |- gradle
 |  ...
 |- src
 |  ...

点击此处下载Gradle Java工程模板。

3.5 Gradle工程构建常用命令

  1. 重新构建工程。任务clean会删除上次构建遗留下来的文件。
> ./gradlew clean build
  1. 使用任务compileJava编译工程的源代码文件。
> ./gradlew compileJava
  1. 可使用任务test运行测试代码来测试工程。
> ./gradlew test
  1. 构建工程并生成jar文件。
> ./gradlew jar
  1. 生成工程的文档。
> ./gradlew javadoc

4 Gradle多模块工程

同时管理多个工程/模块是Gradle的一个重要特色。在一个大型工程的开发过程中,这个大型工程可能会被分解为多个子工程/子模块;各子工程/子模块由各自的开发团队维护。日常开发时,团队自己管理自己的模块,而在产品测试或者发布时,所有的子工程/子模块需要全部打包在一起发布。在这种场景下,Gradle是一款非常合适的工程构建工具。

因为多工程管理和应用的场景各不相同,各个模块之间的依赖关系较为复杂。在本文中,我们仅使用一个简单的例子来展示Gradle的基本使用方法。学习更高级的用法,可参考Gradle的官方文档多模块工程构建

我们假设小水滴正在开发一个大型跨平台(Cross-Platform)工程HelloLittleWaterdrop。它由两个子工程构成。LittleWaterdropPlatform为平台代码库,它向下提供各个平台的兼容与适配;向上提供统一的平台服务。LittleWaterdropApp为一款应用程序,它实现了该工程的业务逻辑(Business Logic)。两个子工程均由Java语言实现。LittleWaeterdropApp依赖于LittlewaterdropPlatform。更准确的说,LittlewaterdropPlatform工程输出一个jar文件,而LittleWaeterdropApp工程依赖于这个jar文件。

4.1 工程结构

首先我们来看一下工程的目录结构。在HelloLittleWaterdrop目录下包含两个目录,分别包含LittleWaterdropPlatform和LittleWaterdropApp工程的文件。在HelloLittleWaterdrop目录下还包含了build.gradle和settings.gradle两个文件,分别用于描述如何构建HelloLittleWaterdrop工程,以及两个子工程/子模块之间的关系。

在主工程HelloLittleWaterdrop目录下的build.gradle文件描述的是主工程的构建过程。两个子工程还分别包含各自的build.gradle的文件,用于分别描述子工程的构建过程。为了简化工程构建的配置,各个子工程中相同的内容可以放置在主工程的build.gradle文件中。在我们接下来讲解的例子中,子工程的build.gradle文件是空的。所有的配置都在主工程的build.gradle文件中。因此,在实际应用中,空白的子工程build.gradle文件是可以删除的。

HelloLittleWaterdrop
 |- LittleWaterdropPlatform
 |  |- build.gradle
 |  |- src
 |  |  |- main
 |  |  |  |- java
 |  |  |  |  |- com
 |  |  |  |  |  |- littlewaterdrop
 |  |  |  |  |  |  |- Platform.java
 |- LittleWaterdropApp
 |  |- build.gradle
 |  |- src
 |  |  |- main
 |  |  |  |- java
 |  |  |  |  |- com
 |  |  |  |  |  |- littlewaterdrop
 |  |  |  |  |  |  |- App.java
 |- build.gradle
 |- settings.gradle

4.2 主工程的settings.gradle文件

主工程的settings.gradle文件非常简单,只有两行。它指定了主工程的名称,和包含的子工程的名称。在运行时,gradle会依次构建各个子工程。

rootProject.name = 'HelloLittleWaterdrop'
include ':LittleWaterdropPlatform', ':LittleWaterdropApp'

4.3 主工程的build.gradle文件

在主工程的build.gradle文件中,主要分为三个部分。第一个部分是allprojects属性的定义。在allprojects属性中,可以为所有的子工程添加属性。例如,下面的配置为主工程和两个子工程添加了一个任务hello。当运行主任务的hello时,子工程的任务也会执行。

allprojects {
    task hello {
        doLast { task ->
            println "I'm $task.project.name"
        }
    }
}

执行结果如下。从执行的结果可以看出,三个工程都执行了任务hello。

> gradle -q hello
I'm HelloLittleWaterdrop
I'm LittleWaterdropApp
I'm LittleWaterdropPlatform

然后,第二个部分是定义子工程的相同属性。在运行时,gradle会将这些属性自动添加到子工程的build.gradle对象中。从下面的配置可以看出,两个子工程都应用了插件java,输出的jar文件的目标运行环境为java 11版本环境。它们都使用Maven库搜索第三方依赖库。它们都依赖于guava库和junit库。

subprojects {
  apply plugin: 'java'
  sourceCompatibility = 11
  targetCompatibility = 11

  repositories {
    mavenCentral()
  }

  dependencies {
    // This dependency is used by the application.
    implementation 'com.google.guava:guava:29.0-jre'

    // Use JUnit test framework
    testImplementation 'junit:junit:4.13'
  }
}

最后,我们配置LittleWaterdropApp工程独有的属性。因为,LittleWaterdropApp是一个应用程序,它不仅输出jar文件,而且还定义了主类(Main Class)。并且,它依赖于子工程LittleWaterdropPlatform输出的jar文件。因此,针对这些不同之处,下面的配置额外的应用了插件application,定义了依赖和主类的类名。

project(':LittleWaterdropApp') {
  apply plugin: 'application'
  dependencies {
      implementation project(':LittleWaterdropPlatform')
  }
  application {
      // Define the main class for the application.
      mainClassName = 'com.littlewaterdrop.App'
  }
}

最后,在主工程的根目录下运行gradle build来构建主工程以及两个子工程。主工程的输出在build目录中。

> gradle build

BUILD SUCCESSFUL in 3s
11 actionable tasks: 11 executed

点击此处下载Gradle Java多工程的模板。

5 结语

本章介绍了通用型工程构建工具Gradle。与Apache Maven相比,Gradle具备更多的优点。例如:Gradle的性能更好,支持更多的编程语言和工程类型;Gradle给予开发人员更多的便利和灵活性。从我们给出的例子也可以看出,通过简单的配置,就能支持一些经典应用场景的构建。

 

上一章
下一章

注册用户登陆后可留言

Copyright  2019 Little Waterdrop, LLC. All Rights Reserved.