Concepts And Notes About Gradle
Posted on 28/02/2020Gradle
闭包(Closure)
闭包在是一个开放的、匿名的代码块,这个代码块可以接受参数,返回返回值。一般的概念的闭包只能引用闭包内部定义的变量,但 Groovy 中的闭包可以代码块之外的变量。
闭包的语法:
{[closureParameters ->] statements}
其中 [closureParameters ->]
表示以 ,
分割的参数列表,->
用于将参数列表和闭包语句分割。以下为闭包一些实例:
{ item++ } // 引用变量 item
{ -> item++ } // 如此定义的闭包,是不接受参数的。
{ println it } // 隐式参数 it
{ it -> println it} // it 作为显示参数调用
{ name -> println name } // name 作为参数调用
// 指定闭包的参数类型
{ String name, int age ->
println "hey, my name is ${name}, and I'm ${age} years old."
}
// 包含多行语句的闭包
{ reader ->
def line = reader.readLine()
line.trim()
}
如何调用闭包:
// 定义闭包
def code = { 123 }
//调用闭包
assert code() == 123
// 调用闭包的call() 方法
assert code.call() == 123
def greeting = { println "Hello, $it."}
//隐式参数的调用
assert greeting('Patrick') == 'Hello, Patrick.'
assert greeting.call('Patrick') == 'Hello, Patrick.'
// 多个参数
def strcat1 = { String... args -> args.join('') }
assert strcat1('ab', 'cd') == 'abcd'
def strcat2 = { String[] args -> args.join('') }
assert strcat2('ab', 'cd') == 'abcd'
def multicat = { int n, String... args -> args.join('') * n }
assert multicat(2, 'ab', 'cd') == 'abcdabcd'
闭包的与 Lambda 表达式的区别
Groovy 中创建的闭包是 Closure
类的实例对象,与 Java8 中的 Lambda 表达式有本质的区别,Java8 中的Lambda 表达式创建的对象可以是任意接口的实例对象,只要该接口声明了一个未实现的方法。此外,Groovy中闭包的委托(Delegation)这一重要的概念在 Lambda 中没有提现。Groovy 中可以设置闭包的委托为任意对象,同时也可以改变闭包的委托策略。这一特性,使得 Groovy 能够设计出优雅的 DSL 成为可能。
委托的 this
, owner
和delegate
this
: 闭包定义所在的直接外部类。owner
:闭包定义所在的直接外部对象,这个直接外部对象可以是类,也可以是一个闭包。delegate
:当访问闭包不存在的属性,或调用闭包的方法时,这些属性的访问或方法的调用转移到第三方对象上,这个第三方对象就是闭包的委托。默认情况下,闭包的委托对象设置为owner
。
this
与 owner
都是返回直接外部对象,不同之处在于 this
的直接外部对象仅限 类,而 owner
的直接外部对象可以是 类或闭包。
// 1
class Enclosing {
void run() {
def whatIsThisObject = { getThisObject() }
assert whatIsThisObject() == this
def whatIsThis = { this }
assert whatIsThis() == this
}
}
// 2
class EnclosedInInnerClass {
class Inner {
Closure c = { this }
}
void run() {
def inner = new Inner()
assert inner.c() == inner
}
}
//3
class NestedClosures {
void run() {
def nestedClosures = {
def c = { this }
c()
}
assert nestedClosures() == this
}
}
// 上述三种情况下,前两种,把 this 替换为 owner,
// 或把 getThisObject() 方法替换为 getOwner() 方法依然成立
// 只有第三种情况,有差异
// owner
class NestedClosures {
void run {
def nestedClosures = {
def c = { owner }
c()
}
assert nestedClosures() == nestedClosures
}
}
// delegate
class Enclosing {
void run() {
def cl1 = { getDelegate() }
def cl2 = { delegate }
assert cl1() == cl2()
assert cl1() == this
def enclosed = {
{ -> delegate }.call()
}
assert enclosed() == enclosed
}
}
delegate 示例:
class Person {
String name
}
class Thing {
Stirng name
}
def upperCaseName = { delegate.name.toUpperCase() }
def p = new Person(name: 'Norman')
def t = new Thing(name: 'Teapot')
uppperCaseName.delegate = p
assert upperCaseName() == 'NORMAN'
upperCaseName.delegate = t
assert upperCaseName() == 'TEAPOT'
delegate 委托策略:
class Person {
String name
def pretty = { "My name is $name" }
String toString() {
pretty()
}
}
class Thing {
String name
}
def p = new Person(name: 'Sarah')
assert p.toString() == 'Sarah'
def t = new Thind(name: 'Teapot')
p.pretty.delegate = t
assert p.toString() == 'Sarah' // 注意,最终还是 Sarah
p.pretty.resolveStrategy = Closure.DELEGATE_FIRST
assert p.toString() == 'Tespot' //此时,结果为 Teapot
委托策略有如下几种:
Closure.OWNER_FIRST
Closure.DELEGATE_FIRST
Closure.OWNER_ONLY
Closure.DELEGATE_ONLY
Closure.TO_SELF
Gradle 的概念
Gradle 的配置是通过编写 Gradle Build Language 实现的,Gradle Build Language 是一门领域特定语言(DSL, Domain Specific Language)。通过这门语言编写出来的配置文件称为 Gradle Script。Gradle Script 有以下特点:
-
Gradle Script 实现了
Script
接口,所以Script
接口的属性和方法可以在 Gradle Script 中直接引用。 -
Gradle Script 又称为 configuration script,因为随着脚本的执行会配置相应的对象。根据配置对象的不同,Gradle又可以分为以下3类:
Gradle Script 类型 Gradle Script 的委托对象 Build Script(build.gradle) Project
Init Script Gradle
Settings Script (settings.gradle) Settings
比如 Build Script 的执行会配置
Project
对象,这个Project
对象就称为 Build Script 的委托对象(Delegate Object)。委托对象定义的属性和方法可以在 Gradle Script 中直接引用。
Build Script 由零或多个语句(statement)和 script block 组成:
- statement: 属性赋值语句,函数调用,局部变量的定义。
- script block: 是一个参数为闭包(Closure)的函数调用,这个闭包是配置delegate 对象的configuration closure。
- Build Script 也是 Groovy script,所以也可以包含 Groovy script 中合法的语句,比如类、方法的定义。
Gradle 的生命周期
Gradle 的执行过程中有三个重要的类,分别是:
Gradle
:执行gradle
命令就会创建的对象,整个构建过程中仅有一个实例。Settings
:Gradle
对象根据settings.gradle
文件创建Settings
对象,通是根据include
函数,获得组成当前项目的子项目名称,并为每个子项目创建一个Project
对象。Project
:每个项目对应一个Project
对象,
Gradle的生命周期分为以下三个阶段:
- 初始化(Initializaiont):Gradle 支持单项目(single project)和多项目(multi-project)的构建。该阶段Gradle 会选择(根据
settings.gradle
配置文件)参与构建的项目,并为其创建一个Project
对象。 - 配置(Configuration):
build.gradle
文件与Project
对象之间是一对一的关系,这个阶段,对Project
对象执行对应的build.gradle
文件中的语句或 script block。 - 执行(Execution):根据命令行参数,选择配置阶段中的任务(task)执行。
Gradle 常用命令
- 当前项目组成情况:
$gradle projects
- 当前项目的依赖:
$ gradle denpencies
- 当前项目支持的任务:
$ gradle tasks
Gradle build script 配置
compile "org.springframework.boot:spring-boot-starter-web"
// 不用某个传递依赖
compile ("org.springframework.boot:spring-boot-starter-web") {
exclude group: 'com.fasterxml.json.core'
}
// 使用比传递依赖新的依赖
compile "com.fasterxml.jason.core:jackson-databind:2.4.3"
// 使用某个比传递依赖老
compile ("org.springframework.boot:spring-boot-starter-web") {
exclude group 'com.fasterxml.json.core'
}
compile "com.fasterxml.json.core:jackson-databind:2.3.1"
References: