Gradle 深度刨析-Project

来源:
三产
最后修订:
2017年03月22日 16:59:10
 437
Gradle 深度刨析

本文转载自:Gradle 深度刨析

基本构建块

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

Project

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

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

输出如下:

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

可以看到,我们确实可以访问到相关的内容。

一个 Project 可以创建新的 Task,添加依赖关系和配置,并应用插件和其他的构建脚本。

生命周期

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

  • 为构建过程创建一个org.gradle.api.initialization.Settings实例
  • 检查settings.gradle脚本,如果存在,这对上面创建的Settings实例进行相应的配置
  • 使用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文件中什么直接添加到项目中,这个文件位于/.gradle(这个路径可以配置【配置后以配置后的目录为准】,后续教程会提及) 目录或项目的根目录下。这些属性可以通过 project 实例访问。

gradle.properties:

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

使用示例:

println projectTestPropValue
println userTestpPopValue

如果在项目根目录及 /.gradle 下 gradle.properties 中有相同的属性的话以 /.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