【项目笔记】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/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值