Gradle学习2
一、Gradle 构建基础
任何一个 Gradle 构建都是由一个或多个 projects 组成。每个 project 包括许多可构建组成部分。每个 project 都由多个 tasks 组成。每个 task 都代表了构建执行过程中的一个原子性操作。如编译,打包,生成 javadoc,发布到某个仓库等操作。
构建脚本
build.gradle
task hello {
doLast {
println 'Hello world!'
}
}
然后在该文件所在目录执行 gradle -q hello
上面的脚本定义了一个叫做 hello 的 task,并且给它添加了一个动作。当执行 gradle hello 的时候, Gralde 便会去调用 hello 这个任务来执行给定操作。这些操作其实就是一个用 groovy 书写的闭包。
doLast 可以缩写为 <<
快速定义任务
build.gradle
task hello << {
println 'Hello world!'
}
- 在 gradle 任务中采用 groovy
task upper << {
String someString = 'mY_nAmE'
println "Original: " + someString
println "Upper case: " + someString.toUpperCase()
}
Output of gradle -q upper
> gradle -q upper
Original: mY_nAmE
Upper case: MY_NAME
或者
- 在 gradle 任务中采用 groovy
task count << {
4.times { print "$it " }
}
Output of gradle -q count
> gradle -q count
0 1 2 3
任务依赖
- 在两个任务之间指明依赖关系
task hello << {
println 'Hello world!'
}
task intro(dependsOn: hello) << {
println "I'm Gradle"
}
Output of gradle -q intro
\> gradle -q intro
Hello world!
I'm Gradle
- 延迟依赖
添加依赖 task 也可以不必首先声明被依赖的 task。(顺序反过来)
taskX 是 在 taskY 之前定义的,这在多项目构建中非常有用。
注意:当引用的任务尚未定义的时候不可使用短标记法来运行任务。
task taskX(dependsOn: 'taskY') << {
println 'taskX'
}
task taskY << {
println 'taskY'
}
\> gradle -q taskX
taskY
taskX
动态任务
- 创建动态任务
4.times { counter ->
task "task$counter" << {
println "I'm task number $counter"
}
}
// gradle -q task1 的输出结果。
Output of gradle -q task1
\> gradle -q task1
I'm task number 1
任务操纵
一旦任务被创建后,任务之间可以通过 API 进行相互访问。这也是与 Ant 的不同之处。比如可以增加一些依赖。
- 通过 API 进行任务之间的通信 - 增加依赖
4.times { counter ->
task "task$counter" << {
println "I'm task number $counter"
}
}
task0.dependsOn task2, task3
Output of gradle -q task0
\> gradle -q task0
I'm task number 2
I'm task number 3
I'm task number 0
- 通过 API 进行任务之间的通信 - 增加任务行为
task hello << {
println 'Hello Earth'
}
hello.doFirst {
println 'Hello Venus'
}
hello.doLast {
println 'Hello Mars'
}
hello << {
println 'Hello Jupiter'
}
Output of gradle -q hello
> gradle -q hello
Hello Venus
Hello Earth
Hello Mars
Hello Jupiter
doFirst 和 doLast 可以进行多次调用。他们分别被添加在任务的开头和结尾。当任务开始执行时这些动作会按照既定顺序进行。其中 << 操作符 是 doLast 的简写方式。
短标记法
每个任务都是一个脚本的属性,你可以访问它
- 以属性的方式访问任务
task hello << {
println 'Hello world!'
}
hello.doLast {
println "Greetings from the $hello.name task."
}
Output of gradle -q hello
\> gradle -q hello
Hello world!
Greetings from the hello task.
对于插件提供的内置任务。这尤其方便(例如:complie)
增加自定义属性
可以为一个任务添加额外的属性。例如,新增一个叫做 myProperty 的属性,用 ext.myProperty 的方式给他一个初始值。这样便增加了一个自定义属性。
- 为任务增加自定义属性
task myTask {
ext.myProperty = "myValue"
}
task printTaskProperties << {
println myTask.myProperty
}
Output of gradle -q printTaskProperties
\> gradle -q printTaskProperties
myValue
调用Ant任务
Gradle 借助 Groovy 对 Ant 任务进行了优秀的整合。Gradle 自带了一个 AntBuilder,在 Gradle 中调用 Ant 任务比在 build.xml 中调用更加的方便和强大。
- 利用 AntBuilder 执行 ant.loadfile
task loadfile << {
def files = file('../antLoadfileResources').listFiles().sort()
files.each { File file ->
if (file.isFile()) {
ant.loadfile(srcFile: file, property: file.name)
println " *** $file.name ***"
println "${ant.properties[file.name]}"
}
}
}
Output of gradle -q loadfile
\> gradle -q loadfile
*** agile.manifesto.txt ***
Individuals and interactions over processes and tools
Working software over comprehensive documentation
Customer collaboration over contract negotiation
Responding to change over following a plan
*** gradle.manifesto.txt ***
Make the impossible possible, make the possible easy and make the easy elegant.
(inspired by Moshe Feldenkrais)
方法抽取
- 利用方法组织脚本逻辑
task checksum << {
fileList('../antLoadfileResources').each {File file ->
ant.checksum(file: file, property: "cs_$file.name")
println "$file.name Checksum: ${ant.properties["cs_$file.name"]}"
}
}
task loadfile << {
fileList('../antLoadfileResources').each {File file ->
ant.loadfile(srcFile: file, property: file.name)
println "I'm fond of $file.name"
}
}
File[] fileList(String dir) {
file(dir).listFiles({file -> file.isFile() } as FileFilter).sort()
}
Output of gradle -q loadfile
\> gradle -q loadfile
I'm fond of agile.manifesto.txt
I'm fond of gradle.manifesto.txt
定义默认任务
Gradle 允许在脚本中定义多个默认任务。
在多项目构建中,每个子项目都可以指定单独的默认任务。如果子项目未进行指定将会调用父项目指定的的默认任务。
defaultTasks 'clean', 'run'
task clean << {
println 'Default Cleaning!'
}
task run << {
println 'Default Running!'
}
task other << {
println "I'm not a default task!"
}
Output of gradle -q
\> gradle -q
Default Cleaning!
Default Running!
Configure by DAG
例如检查已经执行的任务中有没有被释放
task distribution << {
println "We build the zip with version=$version"
}
task release(dependsOn: 'distribution') << {
println 'We release now'
}
gradle.taskGraph.whenReady {taskGraph ->
if (taskGraph.hasTask(release)) {
version = '1.0'
} else {
version = '1.0-SNAPSHOT'
}
}
gradle -q distribution 的输出结果:
Output of gradle -q distribution
\> gradle -q distribution
We build the zip with version=1.0-SNAPSHOT
gradle -q release 的输出结果:
Output of gradle -q release
\> gradle -q release
We build the zip with version=1.0
We release now
二、Gradle Java构建入门
Gradle 是一个通用工具。它可以通过脚本构建任何你想要实现的东西,真正实现开箱即用。但前提是你需要在脚本中编写好代码才行。Gradle 自带了很多插件,并且你也可以很容易的编写和分享自己的插件。Java plugin 作为其中之一,为你提供了诸如编译,测试,打包等一些功能。
Java 插件为工程定义了许多默认值,如Java源文件位置。如果你遵循这些默认规则,那么你无需在你的脚本文件中书写太多代码。当然,Gradle 也允许你自定义项目中的一些规则,实际上,由于对 Java 工程的构建是基于插件的,那么你也可以完全不用插件自己编写代码来进行构建。
一个基本 Java 项目
想用 Java 插件,只需增加如下代码到你的脚本build.gradle里
采用 Java 插件
apply plugin: 'java'
标准目录结构:
project
+build
+src/main/java
+src/main/resources
+src/test/java
+src/test/resources
Gradle 默认会从 src/main/java 搜寻打包源码,在 src/test/java 下搜寻测试源码。
src/main/resources 下的所有文件按都会被打包,所有 src/test/resources 下的文件都会被添加到类路径用以执行测试。
所有文件都输出到 build 下,打包的文件输出到 build/libs 下。
构建项目
Java 插件为你添加了众多任务。但是它们只是在你需要构建项目的时候才能发挥作用。
最常用的就是 build 任务,这会构建整个项目。当你执行 gradle build 时,Gralde 会编译并执行单元测试,并且将 src/main/* 下面 class 和资源文件打包。
构建 Java 项目
运行 gradle build 的输出结果
其余一些较常用的任务有如下几个:
clean:删除 build 目录以及所有构建完成的文件。
assemble:编译并打包 jar 文件,但不会执行单元测试。一些其他插件可能会增强这个任务的功能。例如,如果采用了 War 插件,这个任务便会为你的项目打出 War 包。
check:编译并测试代码。一些其他插件也可能会增强这个任务的功能。例如,如果采用了 Code-quality 插件,这个任务会额外执行 Checkstyle。
外部依赖(build.gradle)【详见 依赖管理基础】
通常,一个 Java 项目拥有许多外部依赖。你需要告诉 Gradle 如何找到并引用这些外部文件。
在 Gradle 中通常 Jar 包都存在于仓库中。仓库可以用来搜寻依赖或发布项目产物。下面是一个采用 Maven 仓库的例子。
(1)添加 Maven 仓库
repositories {
mavenCentral()
}
(2)添加依赖:这里声明了编译期所需依赖 commons-collections 和测试期所需依赖 junit。
dependencies {
compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
testCompile group: 'junit', name: 'junit', version: '4.+'
}
自定义项目
(1)自定义项目
Java 插件为你的项目添加了众多默认配置。这些默认值通常对于一个普通项目来说已经足够了。但如果你觉得不适用修改起来也很简单。
例如:我们为 Java 项目指定了版本号以及所用的 JDK 版本,并且添加一些属性到 mainfest 中。
自定义 MANIFEST.MF
sourceCompatibility = 1.5 //jdk版本
version = '1.0' //指定Java项目版本号
jar {
manifest {
attributes 'Implementation-Title': 'Gradle Quickstart', 'Implementation-Version': version
}
}
可以执行 gradle propertie s来得到项目的属性列表。用这条命令可以看到插件添加的属性以及默认值。
为 test 添加系统属性
test {
systemProperties 'property': 'value'
}
发布 jar 包
需要告诉 Gradle 发布到到哪。在 Gradle 中 jar 包通常被发布到某个仓库中。在下面的例子中,我们会将 jar 包发布到本地目录。当然你也可以发布到远程仓库或多个远程仓库中。
uploadArchives {
repositories {
flatDir {
dirs 'repos'
}
}
}
执行 gradle uploadArchives 以发布 jar 包。
创建Eclipse文件
要把项目导入 Eclipse 中,需要添加另外一个插件到脚本文件中。
apply plugin: 'eclipse'
执行 gradle eclipse 来生成 Eclipse 项目文件。
示例汇总
Java 示例 - 一个完整构建脚本
// 添加插件
apply plugin: 'java'
apply plugin: 'eclipse'
sourceCompatibility = 1.5 // 指定编译.java文件的jdk版本,默认为当前JVM版本
version = '1.0' // 指定项目的版本号
jar { // 自定义 MANIFEST.MF
manifest {
attributes 'Implementation-Title': 'Gradle Quickstart', 'Implementation-Version': version
}
}
repositories { // 添加 Maven 仓库
mavenCentral()
}
dependencies { // 添加依赖
compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
testCompile group: 'junit', name: 'junit', version: '4.+'
}
test { // 为 test 添加系统属性
systemProperties 'property': 'value'
}
uploadArchives { // 发布 jar 包
repositories {
flatDir {
dirs 'repos'
}
}
}
多项目构建
项目结构
Build layout
multiproject/
api/
services/webservice/
shared/
此处有三个工程。api 工程用来生成给客户端用的 jar 文件,这个 jar 文件可以为 XML webservice 提供 Java 客户端。webservice 是一个 web 应用,生成 XML。shared 工程包含的是前述两个工程共用的代码。
- 多项目构建定义
定义一个多项目构建工程需要在根目录(本例中与 multiproject 同级)创建一个setting 配置文件来指明构建包含哪些项目。并且这个文件必需叫 settings.gradle
多项目构建中的 settings.gradle
settings.gradle
include "shared", "api", "services:webservice", "services:shared"
公共配置
对多项目构建而言,总有一些共同的配置。
在根项目上采用配置注入的方式定义一些公共配置。根项目就像一个容器,子项目会迭代访问它的配置并注入到自己的配置中。这样就可以简单的为所有工程定义主配置单了:
subprojects {
apply plugin: 'java'
apply plugin: 'eclipse-wtp'
repositories {
mavenCentral()
}
dependencies {
testCompile 'junit:junit:4.11'
}
version = '1.0'
jar {
manifest.attributes provider: 'gradle'
}
}
为每个子项目都应用了 Java 插件。这意味着我们在前面章节学习的内容在子项目中也都是可用的。所以可以在根项目目录进行编译,测试,打包等所有操作。
工程依赖
同一个构建中可以建立工程依赖,一个工程的 jar 包可以提供给另外一个工程使用。
例如我们可以让 api 工程以依赖于 shared 工程的 jar 包。这样 Gradle 在构建 api 之前总是会先构建 shared 工程。
api/build.gradle
dependencies {
compile project(':shared')
}
打包发布
api/build.gradle
task dist(type: Zip) {
dependsOn spiJar
from 'src/dist'
into('libs') {
from spiJar.archivePath
from configurations.runtime
}
}
artifacts {
archives dist
}
三、依赖管理基础
依赖管理
由如下两部分组成。首先,Gradle 需要知道项目构建或运行所需要的一些文件,以便于找到这些需要的文件,我们称这些输入的文件为项目的依赖;其次,你可能需要构建完成后自动上传到某个地方。我们称这些输出为发布。
大部分工程都不太可能完全自给自足,一般你都会用到其他工程的文件。比如我工程需要 Hibernate 就得把它的类库加进来,比如测试的时候可能需要某些额外 jar 包,包例如JDBC驱动或Ehcache 之类的 Jar 包。
Gradle 需要你告诉它工程的依赖是什么,它们在哪,然后帮你加入构建中。依赖可能需要去远程库下载,比如 Maven 或者 Ivy 库。也可以是本地库,甚至可能是另一个工程。我们称这个过程叫依赖解决。
通常,依赖的自身也有依赖。例如,Hibernate 核心类库就依赖于一些其他的类库。所以,当 Gradle 构建你的工程时,会去找到这些依赖。我们称之为依赖传递。
依赖声明
apply plugin: 'java'
repositories {
mavenCentral()
}
// Hibernate-core.3.6.7.final.jar是编译期必需的依赖。并且它相关的依赖也会一并被加载进来,该段脚本同时还声明项目测试阶段需要 4.0 版本以上的 Junit。同时告诉 Gradle 可以去 Maven 中央仓库去找这些依赖。
dependencies {
compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
testCompile group: 'junit', name: 'junit', version: '4.+'
}
依赖配置
Gradle 中依赖以组的形式来划分不同的配置。每个配置都只是一组指定的依赖。我们称之为依赖配置 。你也可以借由此声明外部依赖。
Java 插件定义了许多标准配置项。这些配置项形成了插件本身的 classpath。
- compile:编译范围依赖在所有的 classpath 中可用,同时它们也会被打包。源代码(src/main/java)编译时的依赖,最常用
- runtime:源代码(src/main/java)执行时依赖。runtime 依赖在运行和测试系统的时候需要,但在编译的时候不需要。比如,你可能在编译的时候只需要 JDBC API JAR,而只有在运行的时候才需要 JDBC 驱动实现
- testCompile:测试代码(src/main/test)编译时的附加依赖
- testRuntime:测试代码(src/main/java)执行时的依赖。测试运行期需要
- archives:项目打包(e.g.jar)时的依赖
不同的插件提供了不同的标准配置,你甚至也可以定义属于自己的配置项。
外部依赖
这种依赖由外部构建或者在不同的仓库中,例如 Maven 中央仓库或 Ivy 仓库中抑或是本地文件系统的某个目录中。
1、定义外部依赖:包含 group,name 和 version 几个属性。根据选取仓库的不同,group 和 version 也可能是可选的。
dependencies {
compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
}
2、快速定义外部依赖:将三个属性拼接在一起即可。“group:name:version”
dependencies {
compile 'org.hibernate:hibernate-core:3.6.7.Final'
}
添加依赖可以有以下方式:
/* 单个依赖 */
compile group:'log4j', name:'log4j', version:'1.2.17'
// 简写 => compile 'log4j:log4j:1.2.17'
/* 以数组形式添加多个依赖*/
compile 'joda-time:joda-time:2.9.2', 'log4j:log4j:1.2.17'
/* 闭包形式,以添加额外配置*/
compile (group:'log4j', name:'log4j', version:'1.2.17'){
// ... 额外配置
}
/* 等价于 */
compile ('log4j:log4j:1.2.17'){
// ... 额外配置
}
仓库
Gradle 是在一个被称之为仓库的地方找寻所需的外部依赖。
仓库是一个按 group,name 和 version 规则进行存储的一些文件。
Gradle 可以支持不同的仓库存储格式,如 Maven 和 Ivy,并且还提供多种与仓库进行通信的方式,如通过本地文件系统或 HTTP。
默认情况下,Gradle 没有定义任何仓库,你需要在使用外部依赖之前至少定义一个仓库,例如 Maven 中央仓库。
一个项目可以采用多个库。Gradle 会按照顺序从各个库里寻找所需的依赖文件,并且一旦找到第一个便停止搜索。
1、使用 Maven 中央仓库
repositories {
mavenCentral()
}
2、使用 Maven 远程仓库
repositories {
maven {
url "http://repo.mycompany.com/maven2"
}
}
3、采用本地 Ivy 目录
repositories {
ivy {
// URL can refer to a local directory
url "../local-repo"
}
}
4、采用 Ivy 远程仓库
repositories {
ivy {
url "http://repo.mycompany.com/repo"
}
}
其他仓库
/* Maven Central respoitory */
repositories {
mavenCentral()
}
/* Maven JCenter respoitory */
repositories {
jcenter()
}
/* Maven local respoitory */
/* 本地仓库是之前下载的依赖,缓存在本地磁盘*/
repositories {
mavenLocal()
}
打包发布
1、jar发布到本地目录
uploadArchives {
repositories {
flatDir {
dirs 'repos'
}
}
}
执行 gradle uploadArchives 以发布 jar 包
2、发布到 Maven 仓库
apply plugin: 'maven'
uploadArchives {
repositories {
mavenDeployer {
repository(url: "file://localhost/tmp/myRepo/")
}
}
}
发布到 Maven 仓库你需要 ‘Maven’ 插件的支持,
执行 gradle uploadArchives,Gradle 便会构建并上传jar 包,同时产生 pom.xml 一起上传到目标仓库。
3、发布到 Ivy 仓库
uploadArchives {
repositories {
ivy {
credentials {
username "username"
password "pw"
}
url "http://repo.mycompany.com"
}
}
}
执行 gradle uploadArchives,Gradle 便会构建并上传你的 jar 包,同时会生成一个 ivy.xml 一起上传到目标仓库。
========== 基本上是W3Cschool内容,之所以弄一遍,是防止自己在看的时候走神,捋一遍 ==========
参考:
gradle下构建的工程目录结构解释:https://www.jianshu.com/p/f33bb06e447e
W3Cschool:https://www.w3cschool.cn/gradle/