转载地址:
http://www.cnblogs.com/CloudTeng/p/3418072.html

  Gradle是一种声明式的构建工具。在执行时,Gradle并不会一开始便顺序执行build.gradle文件中的内容,而是分为两个阶段,第一个阶段是配置阶段,然后才是实际的执行阶段。在配置阶段,Gradle将读取所有build.gradle文件的所有内容来配置Project和Task等,比如设置Project和Task的Property,处理Task之间的依赖关系等。

  虽然很多时候我们只需要照着网上的例子写自己的DSL语句就行了,但是此时我们所知道的也就只有这么多了。如果我们能够了解Gradle DSL的内部工作机制,那么我们便可以达到举一反三的效果。在前面的文章中我们讲到,Gradle的DSL只是Groovy语言的内部DSL,也即必须遵循Groovy的语法规则。现在,让我们先来看看以下非常简单的Task:

task showDescription1 << {    description = 'this is task showDescription'    println description }   task showDescription2 << {    println description } showDescription2.description = 'this is task showDescription'   task showDescription3 << {    println description }  showDescription3 {    description = 'this is task showDescription' }

  以上3个Task完成的功能均相同,即先设置Task的description属性,在将其输出到命令行。但是,他们对description的设置方式是不同的。对于showDescription1,我们在定义一个Task的同时便设置description;对于showDescription2,其本身便是Project的一个Property;而对于showDescription3,我们是在一个和它同名的方法中设置description。

  事实上,对于每一个Task,Gradle都会在Project中创建一个同名的Property,所以我们可以将该Task当作Property来访问,showDescription2便是这种情况。另外,Gradle还会创建一个同名的方法,该方法接受一个闭包,我们可以使用该方法来配置Task,showDescription3便是这种情况。

  要读懂Gradle,我们首先需要了解Groovy语言中的两个概念,一个Groovy中的Bean概念,一个是Groovy闭包的delegate机制。

  Groovy中的Bean和Java中的Bean有一个很大的不同,即Groovy为每一个字段都会自动生成getter和setter,并且我们可以通过像访问字段本身一样调用getter和setter,比如:

class GroovyBeanExample {    private String name }  def bean = new GroovyBeanExample() bean.name = 'this is name' println bean.name

  我们看到,GroovyBeanExample只定义了一个私有的name属性,并没有getter和setter。但是在使用时,我们可以直接对name进行访问,无论时读还是写。事实上,我们并不是在直接访问name属性,当我们执行"bean.name = 'this is name'"时,我们实际调用的是"bean.setName('this is name')",而在调用"println bean.name"时,我们实际调用的是"println bean.getName()"。这里的原因在于,Groovy动态地为name创建了getter和setter,采用像直接访问的方式的目的是为了增加代码的可读性,使它更加自然,而在内部,Groovy依然是在调用setter和getter方法。这样,我们便可以理解上面对showDescription2的description设置原理。

  另外,Gradle大量地使用了Groovy闭包的delegate机制。简单来说,delegate机制可以使我们将一个闭包中的执行代码的作用对象设置成任意其他对象。比如:

class Child {    private String name }  class Parent {    Child child = new Child();     void configChild(Closure c) {       c.delegate = child       c.setResolveStrategy Closure.DELEGATE_FIRST       c()    } }  def parent = new Parent() parent.configChild { name = "child name" }  println parent.child.name

  在上面的例子中,当我们调用configChild()方法时,我们并没有指出name属性是属于Child的,但是它的确是在设置Child的name属性。事实上光从该方法的调用中,我们根本不知道name是属于哪个对象的,你可能会认为它是属于Parent的。真实情况是,在默认情况下,name的确被认为是属于Parent的,但是我们在configChild()方法的定义中做了手脚,使其不再访问Parent中的name(Parent也没有name属性),而是Child的name。在configChild()方法中,我们将该方法接受的闭包的delegate设置成了child,然后将该闭包的ResolveStrategy设置成了DELEGATE_FIRST。这样,在调用configChild()时,所跟闭包中代码被代理到了child上,即这些代码实际上是在child上执行的。此外,闭包的ResolveStrategy在默认情况下是OWNER_FIRST,即它会先查找闭包的owner(这里即parent),如果owner存在,则在owner上执行闭包中的代码。这里我们将其设置成了DELEGATE_FIRST,即该闭包会首先查找delegate(本例中即child),如果找到,该闭包便会在delegate上执行。对于上面的showDescription3,便是这种情况。当然,实际情况会稍微复杂一点,比如showDescription3()方法会在内部调用showDescription3的configure()方法,再在configure()方法中执行闭包中的代码。

  你可能会发现,在使用Gradle时,我们并没有像上面的parent.configChild()一样指明方法调用的对象,而是在build.gradle文件中直接调用task(),apply()和configuration()方法等,这是因为在没有说明调用对象的情况下,Gradle会自动将调用对象设置成当前Project。比如调用apply()方法和调用project.apply()方法的效果是一样的。查查Gradle的Project文档,你会发现这些方法都是Project类的方法。

  另外举个例子,对于configurations()方法(它的作用我们将在后面的文章中讲到),该方法实际上会将所跟闭包的delegate设置成ConfigurationContainer,然后在该ConfigurationContainer上执行闭包中的代码。再比如,dependencies()方法,该方法会将所跟闭包的delegate设置成DependencyHandler。

  还有,Project还定义了configure(Object object,Closure configureClosure)方法,该方法是专门用来配置对象的(比如Task),它会将configureClosure的delegate设置成object,之后configureClosure中的执行代码其实是在object上执行的。和Groovy Bean一样,delegate机制的一个好处是可以增加所创建DSL的可读性。

Gradle学习系列之读懂Gradle语法的更多相关文章

  1. Gradle学习系列之三——读懂Gradle语法

    在本系列的上篇文章中,我们讲到了创建Task的多种方法,在本篇文章中,我们将学习如何读懂Gradle. 请通过以下方式下载本系列文章的Github示例代码: git clone https://git ...

  2. Gradle学习系列之一——Gradle快速入门

    这是一个关于Gradle的学习系列,其中包含以下文章: Gradle快速入门 创建Task的多种方法 读懂Gradle语法 增量式构建 自定义Property 使用java Plugin 依赖管理 构 ...

  3. Gradle学习系列之一——Gradle快速入门(转)

    这是一个关于Gradle的学习系列,其中包含以下文章: Gradle快速入门 创建Task的多种方法 读懂Gradle语法 增量式构建 自定义Property 使用java Plugin 依赖管理 构 ...

  4. Gradle学习系列之四——增量式构建

    在本系列的上篇文章中,我们讲到了如何读懂Gradle的语法,在本篇文章中,我们将讲到增量式地构建项目. 请通过以下方式下载本系列文章的Github示例代码: git clone https://git ...

  5. Gradle学习系列之二——创建Task的多种方法

    在本系列的上篇文章中,我们讲到了Gradle入门,在本篇文章中我们将讲到创建Task的多种方法. 请通过以下方式下载本系列文章的Github示例代码: git clone https://github ...

  6. Gradle学习系列(一)

    今天就开始学习Gradle构建了,听说很牛X.本篇内容就带领我初步窥探Gradle的世界.     1.什么是Gradle       相信之前都接触过用Ant或者Meavn进行项目的构建,两者各有千 ...

  7. 读懂 Gradle 的 DSL

    现在 Android 开发免不了要和 Gradle 打交道,所有的 Android 开发肯定都知道这么在 build.gradle 中添加依赖,或者添加配置批量打包,但是真正理解这些脚本的人恐怕很少. ...

  8. Gradle学习总结——抓重点学Gradle

    前言 网上关于Gradle的教程很多,但很多都是以"面"切入- 通过大量讲解其用法及其API分类来阐述.但Gradle API使用技巧众多,API更是成千上百,臣妾记不住呀.个人深 ...

  9. Gradle学习系列之九——自定义Task类型

    在本系列的上篇文章中,我们学习了多Project构建,在本篇文章中,我们将学到如何自定义Task类型. 请通过以下方式下载本系列文章的Github示例代码: git clone https://git ...

随机推荐

  1. [leetcode]34.Find First and Last Position of Element in Sorted Array找区间

    Given an array of integers nums sorted in ascending order, find the starting and ending position of ...

  2. mysql数据库导入与导出

    导出 导出数据和表结构: mysqldump -u用户名 -p 数据库名 > 数据库名.sql mysqldump -uroot -p dbname > dbname .sql      ...

  3. 获取CNVD的cookie

    def getCookie(self): #获取cookie spiderFirefox = webdriver.Firefox() spiderFirefox.get("http://ww ...

  4. 新版本wireshark tshark使用

    Wireshark-tshark wireshark 指令模式 => tshark Windows 及Linux 可至安裝目錄執行>tshark tshark.exe -i 7(利用-D找 ...

  5. 微信小程序开发 - 用户授权登陆

    准备:微信开发者工具下载地址:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html 微信小程序开发文档:htt ...

  6. 【转】背后的故事之 - 快乐的Lambda表达式(一)

    快乐的Lambda表达式(二) 自从Lambda随.NET Framework3.5出现在.NET开发者眼前以来,它已经给我们带来了太多的欣喜.它优雅,对开发者更友好,能提高开发效率,天啊!它还有可能 ...

  7. maven打包自定义jar到maven仓库

    mvn install:install-file -Dfile=F:/Sdk4j.jar -DgroupId=com.sdk4j -DartifactId=sdk4j -Dversion=1.0 -D ...

  8. john and hydra using de-ice1.100

    配置IP  ipconfig etho 192.168.179.111 http://192.168.179.111/index2.php curl http://192.168.179.111/in ...

  9. 我的第一个python爬虫

    我的第一个爬虫,哈哈,纯面向过程 实现目标: 1.抓取本地conf文件,其中的URL地址,然后抓取视频名称以及对应的下载URL 2.抓取URL会单独写在本地路径下,以便复制粘贴下载 废话补多少,代码实 ...

  10. centos下安装nethogs

    wget https://github.com/raboof/nethogs/archive/v0.8.1.tar.gzyum install libpcap-develtar zxvf v0.8.1 ...