国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - Java使用自動化部署工具Gradle中的任務設定教程

Java使用自動化部署工具Gradle中的任務設定教程

2020-05-18 12:22hi大頭鬼hi JAVA教程

Grandle使用同樣運行于JVM上的Groovy語言編寫,本文會對此進行初步夠用的講解,接下來我們就一起來看一下Java使用自動化部署工具Gradle中的任務設定教程:

tasks
下面的代碼展示了三個Gradle task,稍后會講解這三者的不同。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
task myTask {
println "Hello, World!"
}
 
task myTask {
doLast {
println "Hello, World!"
}
}
 
task myTask << {
println "Hello, World!"
}

我的目的是創建一個task,當它執行的時候會打印出來”Hello, World!”。當我第一次創建task的時候,我猜測應該是這樣來寫的:

?
1
2
3
task myTask {
println "Hello, World!"
}

現在,試著來執行這個myTask,在命令行輸入gradle myTask,打印如下:

?
1
2
3
user$ gradle myTask
Hello, World!
:myTask UP-TO-DATE

這個task看起來起作用了。它打印了”Hello, World!”。
但是,它其實并沒有像我們期望的那樣。下面我們來看看為什么。在命令行輸入gradle tasks來查看所有可用的tasks。

?
1
2
3
4
5
6
7
8
9
10
11
12
user$ gradle tasks
Hello, World!
:tasks
 
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
 
Build Setup tasks
-----------------
init - Initializes a new Gradle build. [incubating]
..........

等等,為什么”Hello, World!”打印出來了?我只是想看看有哪些可用的task,并沒有執行任何自定義的task!
原因其實很簡單,Gradle task在它的生命周期中有兩個主要的階段:配置階段 和 執行階段。
可能我的用詞不是很精確,但這的確能幫助我理解tasks。

Gradle在執行task之前都要對task先進行配置。那么問題就來了,我怎么知道我的task中,哪些代碼是在配置過程中執行的,哪些代碼是在task執行的時候運行的?答案就是,在task的最頂層的代碼就是配置代碼,比如:

?
1
2
3
4
task myTask {
def name = "Pavel" //<-- 這行代碼會在配置階段執行
println "Hello, World!"////<-- 這行代碼也將在配置階段執行
}

這就是為什么我執行gradle tasks的時候,會打印出來”Hello, World!”-因為配置代碼被執行了。但這并不是我想要的效果,我想要”Hello, World!”僅僅在我顯式的調用myTask的時候才打印出來。為了達到這個效果,最簡單的方法就是就是使用Task#doLast()方法。

?
1
2
3
4
5
6
task myTask {
def text = 'Hello, World!' //configure my task
doLast {
println text //this is executed when my task is called
}
}

現在,”Hello, World!”僅僅會在我執行gradle myTask的時候打印出來。Cool,現在我已經知道如何配置以及使task做正確的事情。還有一個問題,最開始的例子中,第三個task的<<符號是什么意思?

?
1
2
3
task myTask2 << {
println "Hello, World!"
}

這其實只是doLast的一個語法糖版本。它和下面的寫法效果是一樣的:

?
1
2
3
4
5
task myTask {
doLast {
println 'Hello, World!' //this is executed when my task is called
}
}

但是,這種寫法所有的代碼都在執行部分,沒有配置部分的代碼,因此比較適合那些簡小不需要配置的task。一旦你的task需要配置,那么還是要使用doLast的版本。

語法

Gradle腳本是使用Groovy語言來寫的。Groovy的語法有點像Java,希望你能接受它。
如果你對Groovy已經很熟悉了,可以跳過這部分了。
Groovy中有一個很重要的概念你必要要弄懂–Closure(閉包)

Closures

Closure是我們弄懂Gradle的關鍵。Closure是一段單獨的代碼塊,它可以接收參數,返回值,也可以被賦值給變量。和Java中的Callable接口,Future類似,也像函數指針,你自己怎么方便理解都好。。。

關鍵是這塊代碼會在你調用的時候執行,而不是在創建的時候。看一個Closure的例子:

?
1
2
3
4
5
6
def myClosure = { println 'Hello world!' }
 
//execute our closure
myClosure()
 
#output: Hello world!

下面是一個接收參數的Closure:

?
1
2
3
4
5
6
def myClosure = {String str -> println str }
 
//execute our closure
myClosure('Hello world!')
 
#output: Hello world!

如果Closure只接收一個參數,可以使用it來引用這個參數:

?
1
2
3
4
5
6
def myClosure = {println it }
 
//execute our closure
myClosure('Hello world!')
 
#output: Hello world!

接收多個參數的Closure:

?
1
2
3
4
5
6
def myClosure = {String str, int num -> println "$str : $num" }
 
//execute our closure
myClosure('my string', 21)
 
#output: my string : 21

另外,參數的類型是可選的,上面的例子可以簡寫成這樣:

?
1
2
3
4
5
6
def myClosure = {str, num -> println "$str : $num" }
 
//execute our closure
myClosure('my string', 21)
 
#output: my string : 21

很酷的是Closure中可以使用當前上下文中的變量。默認情況下,當前的上下文就是closure被創建時所在的類:

?
1
2
3
4
5
def myVar = 'Hello World!'
def myClosure = {println myVar}
myClosure()
 
#output: Hello world!

另外一個很酷的點是closure的上下文是可以改變的,通過Closure#setDelegate()。這個特性非常有用:

?
1
2
3
4
5
6
7
8
9
10
def myClosure = {println myVar} //I'm referencing myVar from MyClass class
MyClass m = new MyClass()
myClosure.setDelegate(m)
myClosure()
 
class MyClass {
 def myVar = 'Hello from MyClass!'
}
 
#output: Hello from MyClass!

正如你鎖看見的,在創建closure的時候,myVar并不存在。這并沒有什么問題,因為當我們執行closure的時候,在closure的上下文中,myVar是存在的。這個例子中。因為我在執行closure之前改變了它的上下文為m,因此myVar是存在的。

把closure當做參數傳遞

closure的好處就是可以傳遞給不同的方法,這樣可以幫助我們解耦執行邏輯。前面的例子中我已經展示了如何把closure傳遞給一個類的實例。下面我們將看一下各種接收closure作為參數的方法:

1.只接收一個參數,且參數是closure的方法: myMethod(myClosure)
2.如果方法只接收一個參數,括號可以省略: myMethod myClosure
3.可以使用內聯的closure: myMethod {println ‘Hello World'}
4.接收兩個參數的方法: myMethod(arg1, myClosure)
5.和4類似,單數closure是內聯的: myMethod(arg1, { println ‘Hello World' })
6.如果最后一個參數是closure,它可以從小括號從拿出來: myMethod(arg1) { println ‘Hello World' }

這里我只想提醒你一下,3和6的寫法是不是看起來很眼熟?

Gradle例子

現在我們已經了解了基本的語法了,那么如何在Gradle腳本中使用呢?先看下面的例子吧:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
buildscript {
 repositories {
 jcenter()
 }
 dependencies {
 classpath 'com.android.tools.build:gradle:1.2.3'
 }
}
 
allprojects {
 repositories {
 jcenter()
 }
}

知道了Groovy的語法,是不是上面的例子就很好理解了?
首先就是一個buildscript方法,它接收一個closure:   

?
1
def buildscript(Closure closure)

接著是allprojects方法,它也接收一個closure參數:

   

?
1
def allprojects(Closure closure)

其他的都類似。。。

現在看起來容易多了,但是還有一點不明白,那就是這些方法是在哪里定義的?答案就是Project

Project

這是理解Gradle腳本的一個關鍵。

構建腳本頂層的語句塊都會被委托給Project的實例
這就說明Project正是我要找得地方。
在Project的文檔頁面搜索buildscript方法,會找到buildscript{} script block(腳本塊).等等,script block是什么鬼?根據文檔:

script block就是只接收closure作為參數的方法
繼續閱讀buildscript的文檔,文檔上說Delegates to: ScriptHandler from buildscript。也就是說,我們傳遞給buildscript方法的closure,最終執行的上下文是ScriptHandler。在上面的例子中,我們的傳遞給buildscript的closure調用了repositories(closure)和dependencies(closure)方法。既然closure被委托給了ScriptHandler,那么我們就去ScriptHandler中尋找dependencies方法。

找到了void dependencies(Closure configureClosure),根據文檔,dependencies是用來配置腳本的依賴的。而dependencies最終又是委托到了DependencyHandler。

看到了Gradles是多么廣泛的使用委托了吧。理解委托是很重要滴。

Script blocks

默認情況下,Project中預先定義了很多script block,但是Gradle插件允許我們自己定義新的script blocks!
這就意味著,如果你在build腳本頂層發了一些{…},但是你在Gradle的文檔中卻找不到這個script blocks或者方法,絕大多情況下,這是一些來自插件中定義的script block。

android Script block

我們來看看默認的Android app/build.gradle文件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apply plugin: 'com.android.application'
 
android {
 compileSdkVersion 22
 buildToolsVersion "22.0.1"
 
 defaultConfig {
 applicationId "com.trickyandroid.testapp"
 minSdkVersion 16
 targetSdkVersion 22
 versionCode 1
 versionName "1.0"
 }
 buildTypes {
 release {
 minifyEnabled false
 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
 }
 }
}

Task順序

我注意到我在使用Gradle的時候遇到的大多數問題都是和task的執行順序有關的。很明顯如果我的構建會工作的更好如果我的task都是在正確的時候執行。下面我們就深入了解一下如何更改task的執行順序。

dependsOn

我認為最直接的方式來說明的你task的執行時依賴別的task的方法就是使用dependsOn方法。
比如下面的場景,已經存在task A,我們要添加一個task B,它的執行必須要在A執行完之后:

Java使用自動化部署工具Gradle中的任務設定教程

這是一個很簡單的場景,假定A和B的定義如下:

?
1
2
task A << {println 'Hello from A'}
task B << {println 'Hello from B'}

只需要簡單的調用B.dependsOn A,就可以了。
這意味著,只要我執行task B,task A都會先執行。

?
1
2
3
4
5
paveldudka$ gradle B
:A
Hello from A
:B
Hello from B

另外,你也可以在task的配置區中來聲明它的依賴:

?
1
2
3
4
5
6
7
task A << {println 'Hello from A'}
task B {
 dependsOn A
 doLast {
 println 'Hello from B'
 }
}

如果我們想要在已經存在的task依賴中插入我們的task該怎么做呢?

Java使用自動化部署工具Gradle中的任務設定教程

過程和剛才類似。假定已經存在如下的task依賴:

?
1
2
3
4
5
6
task A << {println 'Hello from A'}
task B << {println 'Hello from B'}
task C << {println 'Hello from C'}
 
B.dependsOn A
C.dependsOn B

加入我們的新的task

?
1
2
3
task B1 << {println 'Hello from B1'}
B1.dependsOn B
C.dependsOn B1

輸出:

?
1
2
3
4
5
6
7
8
9
paveldudka$ gradle C
:A
Hello from A
:B
Hello from B
:B1
Hello from B1
:C
Hello from C

注意dependsOn把task添加到依賴的集合中,所以依賴多個task是沒有問題的。

Java使用自動化部署工具Gradle中的任務設定教程

?
1
2
3
task B1 << {println 'Hello from B1'}
B1.dependsOn B
B1.dependsOn Q

輸出:

?
1
2
3
4
5
6
7
8
9
paveldudka$ gradle B1
:A
Hello from A
:B
Hello from B
:Q
Hello from Q
:B1
Hello from B1

mustRunAfter

現在假定我又一個task,它依賴于其他兩個task。這里我使用一個真實的場景,我有兩個task,一個單元測試的task,一個是UI測試的task。另外還有一個task是跑所有的測試的,它依賴于前面的兩個task。

Java使用自動化部署工具Gradle中的任務設定教程

?
1
2
3
4
5
6
task unit << {println 'Hello from unit tests'}
task ui << {println 'Hello from UI tests'}
task tests << {println 'Hello from all tests!'}
 
tests.dependsOn unit
tests.dependsOn ui

輸出:

?
1
2
3
4
5
6
7
paveldudka$ gradle tests
:ui
Hello from UI tests
:unit
Hello from unit tests
:tests
Hello from all tests!

盡管unitest和UI test會子啊test task之前執行,但是unit和ui這兩個task的執行順序是不能保證的。雖然現在來看是按照字母表的順序執行,但這是依賴于Gradle的實現的,你的代碼中絕對不能依賴這種順序。
由于UI測試時間遠比unit test時間長,因此我希望unit test先執行。一個解決辦法就是讓ui task依賴于unit task。

Java使用自動化部署工具Gradle中的任務設定教程

?
1
2
3
4
5
6
7
task unit << {println 'Hello from unit tests'}
task ui << {println 'Hello from UI tests'}
task tests << {println 'Hello from all tests!'}
 
tests.dependsOn unit
tests.dependsOn ui
ui.dependsOn unit // <-- I added this dependency

輸出:

?
1
2
3
4
5
6
7
paveldudka$ gradle tests
:unit
Hello from unit tests
:ui
Hello from UI tests
:tests
Hello from all tests!

現在unit test會在ui test之前執行了。
但是這里有個很惡心的問題,我的ui測試其實并不依賴于unit test。我希望能夠單獨的執行ui test,但是這里每次我執行ui test,都會先執行unit test。
這里就要用到mustRunAfter了。mustRunAfter并不會添加依賴,它只是告訴Gradle執行的優先級如果兩個task同時存在。比如我們這里就可以指定ui.mustRunAfter unit,這樣如果ui task和unit task同時存在,Gradle會先執行unit test,而如果只執行gradle ui,并不會去執行unit task。

?
1
2
3
4
5
6
7
task unit << {println 'Hello from unit tests'}
task ui << {println 'Hello from UI tests'}
task tests << {println 'Hello from all tests!'}
 
tests.dependsOn unit
tests.dependsOn ui
ui.mustRunAfter unit

輸出:

?
1
2
3
4
5
6
7
paveldudka$ gradle tests
:unit
Hello from unit tests
:ui
Hello from UI tests
:tests
Hello from all tests!

依賴關系如下圖:

Java使用自動化部署工具Gradle中的任務設定教程

mustRunAfter在Gradle2.4中目前還是實驗性的功能。
finalizedBy

現在我們已經有兩個task,unit和ui,假定這兩個task都會輸出測試報告,現在我想把這兩個測試報告合并成一個:

Java使用自動化部署工具Gradle中的任務設定教程

?
1
2
3
4
5
6
7
8
9
10
task unit << {println 'Hello from unit tests'}
 
task ui << {println 'Hello from UI tests'}
task tests << {println 'Hello from all tests!'}
task mergeReports << {println 'Merging test reports'}
 
tests.dependsOn unit
tests.dependsOn ui
ui.mustRunAfter unit
mergeReports.dependsOn tests

現在如果我想獲得ui和unit的測試報告,執行task mergeReports就可以了。

?
1
2
3
4
5
6
7
8
9
paveldudka$ gradle mergeReports
:unit
Hello from unit tests
:ui
Hello from UI tests
:tests
Hello from all tests!
:mergeReports
Merging test reports

這個task是能工作,但是看起來好笨啊。mergeReports從用戶的角度來看感覺不是特別好。我希望執行tests task就可以獲得測試報告,而不必知道mergeReports的存在。當然我可以把merge的邏輯挪到tests task中,但我不想把tests task搞的太臃腫,我還是繼續把merge的邏輯放在mergeReports task中。
finalizeBy來救場了。顧名思義,finalizeBy就是在task執行完之后要執行的task。修改我們的腳本如下:

?
1
2
3
4
5
6
7
8
9
10
11
task unit << {println 'Hello from unit tests'}
task ui << {println 'Hello from UI tests'}
task tests << {println 'Hello from all tests!'}
task mergeReports << {println 'Merging test reports'}
 
tests.dependsOn unit
tests.dependsOn ui
ui.mustRunAfter unit
mergeReports.dependsOn tests
 
tests.finalizedBy mergeReports

現在執行tests task就可以拿到測試報告了:

?
1
2
3
4
5
6
7
8
9
paveldudka$ gradle tests
:unit
Hello from unit tests
:ui
Hello from UI tests
:tests
Hello from all tests!
:mergeReports
Merging test reports

 

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲 欧美 另类 综合 偷拍 | 欧美国产精品一区 | jav成人av免费播放 | 日日嗨av一区二区三区四区 | 超碰成人免费 | 九九亚洲视频 | 一区二区在线视频 | 国产高清在线 | 欧美亚洲免费 | 久草中文在线 | 一级一片免费 | 一区二区三区四区精品 | 日韩中文字幕在线观看视频 | 成人在线播放网站 | 一二区视频 | 这里只有精品视频 | 美女视频黄的免费 | 超碰在线看 | 日韩av片无码一区二区不卡电影 | 欧美一区二区三区视频在线观看 | av免费资源| 中文精品在线 | 中文字幕在线视频观看 | 色噜噜视频在线观看 | 亚洲激情av | 欧美精品久久久久 | 国产精品成人在线观看 | 日韩在线观看第一页 | 色综合色综合网色综合 | 亚洲一区二区在线 | 亚洲免费中文字幕 | 日韩中文字幕一区二区 | 毛片链接| 欧美一区二区三区在线观看视频 | 女人爽到高潮aaaa电影 | 中文精品一区二区 | 97色在线视频 | 波多野结衣先锋影音 | a在线观看| 国产精品久久久久久久久久 | 日韩精品一区二区三区视频播放 |