Gradle 深度刨析

基本构建块

每一个 Gradle 构建都包含三个基本概念:project、task 和 property。
每一个构建包含至少一个 project、一个或多个 task。project 和 task 暴露的属性能够用来控制构建。
Gradle 的核心组件直接的依赖关系以下:Gradle 的核心组件直接的依赖关系
在多项目构建中,一个 project 能够依赖于其余的 project 。在同一个 project 中一个 task 能够依赖一个或多个 task。html

Project

org.gradle.api.Project 是主要的与 Gradle 构建文件交换的接口,提供了 Gralde 全部特征的编程访问方式(例如tTask的建立以及依赖的管理)。在调用对应API时无需使用 project 变量,由于 Gradle 会默认你使用的是 Project 的实例,java

setDescription("project 描述")//在不显式使用 project 变量的状况下设置项目描述
println "项目 $name 的描述:"+ description //在不使用 project 变量的状况下经过 Groovy 语法来访问 name 以及  description 属性 【这两个属性都是Project对象的属性】

输出以下:shell

coderknock@Sanchan:/mnt/d/Windows/Desktop/LearnGradle/Gradle构建原理$ gradle build
Starting a Gradle Daemon (subsequent builds will be faster)
> Configuring > 0/1 projects > root project > Compiling /mnt/d/Windows/Desktop/LearnGradle/Gradle构建原理/build.gradle i项目 Gradle构建原理 的描述:project 描述
:buildEnvironment

------------------------------------------------------------
Root project - project 描述
------------------------------------------------------------

classpath
No dependencies

BUILD SUCCESSFUL

Total time: 15.786 secs

能够看到,咱们确实能够访问到相关的内容。express

一个 Project 能够建立新的 Task,添加依赖关系和配置,并应用插件和其余的构建脚本。编程

生命周期

“build.gradle” 文件与Project 实例是一一对应的。在构建初始化时,Gradle 为每一个参与到构建过程的项目都建立了一个 Project 对象,操做以下:api

  • 为构建过程建立一个org.gradle.api.initialization.Settings实例闭包

  • 检查settings.gradle脚本,若是存在,这对上面建立的Settings实例进行相应的配置app

  • 使用Settings实例做为配置信息建立Project层次的实例模块化

  • 最后,循环检擦每一个相关的项目,若是存在"build.gradle"文件,则根据该文件对项目对应的Project对象进行配置。项目的检查是横向进行的,这样一个项目老是会在其子项目以前进行检测、配置。这个顺序能够经过调用evaluationDependsOnChildren() 进行修改、或者经过evaluationDependsOn(String)方法添加一个明确的检查依赖关系单元测试

Tasks(任务)

在默认状况下,每一个新建立的 Task 都是org.gradle.api.DefaultTask类型。DefaultTask里全部的属性都是private的,可是提供了gettersetter。Groovy提供的语法糖能够直接使用属性名使用属性。

一个项目基本上是一个Task对象的集合。每一个Task的执行一起基本的工做,如编译类文件,或运行单元测试,或压缩war文件。咱们能够经过实现org.gradle.api.task.TaskContainer接口的类的名为create的方法(该方法是一个多重载的方法)来添加Task,例如TaskContainer.create(String),还可使用TaskContainer中的一些方法来查找已经存在的Task,例如TaskCollection.getByName(String)
第一个 Gradle 脚本及简单命令 的学习中咱们对 Task 就已经有过接触,而且使用过其中一些较为重要的功能:任务动做(task action)以及任务依赖(task dependency)。

Task action(任务动做)

任务动做定义了一个任务执行时的最小工做单元,能够是简单的输出,也能够是诸如编译等较为复杂的工做。例如第一个 Gradle 脚本及简单命令 中的:

task helloworldSort {
    //doLast 就是 Task 中的一个任务动做
    doLast{
        print 'Hello world!'
    }
}
Task dependency(任务依赖)

但一个任务运行时须要先运行另外一个任务,这两个任务间就须要有任务依赖。例如第一个 Gradle 脚本及简单命令 中的:

// 任务依赖
yayGradle0.dependsOn startSession
/* 任务执行的顺序 startSession -> yayGradle0 -> yayGradle1 -> yayGradle2 -> groupTherapy */
// 任务依赖
task groupTherapy(dependsOn: yayGradle2) << {
    println 'groupTherapy'
}

以上就是任务依赖的两种使用方法。
下面是 Task 的API:
任务Task

Dependencies(依赖项)

一个项目为了完成构建工做,一般会有数个依赖。此外,项目一般会产生一系列的其余项目可使用的工件。这些依赖项按配置分组,能够从资料库检出或上传本身的依赖项到资料库。getConfigurations()方法返回的ConfigurationContainer用于管理配置相关信息。 getDependencies()方法返回的DependencyHandler用来管理依赖项相关信息。 ArtifactHandler.getArtifacts()方法返回管理工件相关信息。 getRepositories()方法返回的RepositoryHandler用来管理存储库相关信息。

多项目构建(Multi-project Builds)

多项目会被排成的一个层次结构。一个项目有一个名称以及可以惟一标识该层次结构中的彻底限定的路径。

插件(Plugins)

插件能够用于模块化 以及重用项目配置。可使用PluginAware.apply(java.util.Map)方法,应用插件或经过使用插件脚本块。

plugins {
     id "org.company.myplugin" version "1.3"
 }

以上就是一个简单的插件脚本块。

属性(Properties)

每一个ProjectTask实例都提供了能够经过gettersetter方法访问的属性。
Gradle 执行项目的构建文件来配置对应的Project实例。任何属性或您的脚本使用的方法是经过授予关联的Project对象来实现的。这意味着,你能够在您的脚本直接使用Project接口上的任何方法和属性。
例如︰

defaultTasks('some-task')  // Project.defaultTasks()
 reportsDir = file('reports') // Project.file() and the Java Plugin

您也能够访问使用该属性的实例来访问其属性,在某些状况下,这可使脚本更清晰。例如,您可使用project.name来访问该项目的名称。
一个项目有 6个属性 “范围”用于搜索属性。您能够经过构建文件中的名称或经过调用项目的property(String))方法访问这些属性。5个属性“范围”是:

  1. Project对象自己。此范围包括Project实现类声明的属性的getter和setter。例如,getRootProject())可做为rootProject的属性访问方式。此范围的属性是可读或可写的,存在对相应 getter 和 setter 方法。

  2. 项目的额外属性。每一个项目都维护一个额外属性的映射,能够包含任意 名称 - >值 对。一旦定义,该范围的属性是可读和可写的。有关详细信息,请参阅其余属性

  3. 经过添加插件将扩展添加到项目中。每一个扩展都是只读属性,与扩展具备相同的名称。

  4. 经过插件将约定属性添加到项目中。插件能够经过项目的Convention对象向项目添加属性和方法。此范围的属性能够是可读或可写的,这取决于约定对象。

  5. 项目的任务。能够经过使用其名称做为属性名称来访问任务。此范围的属性是只读的。例如,调用的任务compile可做为compile 属性访问。

  6. 继承自父级项目的扩展属性和惯例属性,递归到根项目。此做用域的属性为只读。

当读取属性时,项目按顺序搜索上述范围,并从其找到属性的第一个范围返回值。若是未找到,将抛出异常。查看property(String))更多详细信息。

编写属性时,项目按顺序搜索上述范围,并将其属性设置在第一个做用域中,该属性位于其中。若是未找到,将抛出异常。查看setProperty(String, Object))更多详细信息。

扩展属性

Gradle对的不少领域模型类提供了特别的属性支持,在内部,这些属性以键值对的形式存储。全部扩展的属性必须经过“ext”命名空间进行定义。一旦扩展的属性被定义,它能够直接在全部的对象(在下面的状况下分别是ProjectTasksubprojects)可用,而且能够被读取和更新。只须要在最初宣布经过命名空间来完成。

project.ext.prop1 = "foo"
ext{
  prop2="test"
}
task doStuff {
     ext.prop3 = "bar"
 }
//下面的方法官方文档中这样写,可是实验时会报错  "ext.$({ -> ... })" is a method call expression, but it should be a variable expression at line: 10 column: 28. File: _BuildScript_ @ line 10, column 28.
//subprojects { ext.${prop4} = false }
ext.prop5=23

println prop1 //会正常输出
println prop2 //会正常输出

//println prop3 //这样调用会报错 Could not get unknown property 'prop3' for root project 'Gradle构建原理' of type org.gradle.api.Project.这也证明了默认使用的是 project 实例
println doStuff.prop3 //会正常输出
println prop5 //会正常输出

经过“ext”或经过拥有的对象来读取扩展的属性。

ext.isSnapshot = version.endsWith("-SNAPSHOT")
if (isSnapshot) {
     // do snapshot stuff
}

扩展属性也能够经过属性文件来提供。

属性文件

Gradle 属性能够经过在 gradle.properties文件中什么直接添加到项目中,这个文件位于<USER_HOME>/.gradle(这个路径能够配置【配置后以配置后的目录为准】,后续教程会说起) 目录或项目的根目录下。这些属性能够经过 project 实例访问。

gradle.properties:

projectTestPropValue=D:\Windows\Desktop\LearnGradle\projectTestPropValue
userTestpPopValue=E:\gradle_repo\.gradle\projectTestPropValue

使用示例:

println projectTestPropValue
println userTestpPopValue

若是在项目根目录及 <USER_HOME>/.gradle 下 gradle.properties 中有相同的属性的话以 <USER_HOME>/.gradle 中为准。

声明属性的其余方式

对于扩展属性以及属性文件两种方式外,还有声明自定义变量及值的方式以及下面这些方式声明属性:

  • 项目属性经过 -P 命令行选项提供:
    运行命令时使用:gradle build -P rootTestPropValue=123

  • 系统属性经过 -D 命令行选项提供
    运行命令时使用:gradle build -D rootTestPropValue=123

  • 环境属性经过系统环境变量设置:
    ORG_GRADLE_PROJECT_propertyName=值

动态方法

一个项目有5种方法“范围”,它搜索方法:

  1. Project对象自己。

  2. 构建文件。该项目搜索在构建文件中声明的匹配方法。

  3. 插件添加到项目的扩展。每一个扩展可用做接受闭包或Action做为参数的方法。

  4. 经过插件将约定方法添加到项目中。插件能够经过项目的Convention对象向项目添加属性和方法。

  5. 项目的任务。为每一个任务添加一个方法,使用任务的名称做为方法名称并获取单个闭包或Action参数。该方法Task.configure(groovy.lang.Closure))

  6. 使用提供的闭包调用关联任务的方法。例如,若是项目有一个被调用的任务compile,那么将添加一个方法,并带有如下签名:void compile(Closure configureClosure)。

  7. 父项目的方法,递归到根项目。

  8. 项目的属性,其值为闭包。封闭被视为一种方法,并使用提供的参数进行调用。该物业的位置如上所述。

下面是 Project 的API:
Project API

下面是 PluginAware 的API:

PluginAware API

相关文章
相关标签/搜索