最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java使用自動(dòng)化部署工具Gradle中的任務(wù)設(shè)定教程

 更新時(shí)間:2016年06月18日 16:52:04   作者:hi大頭鬼hi  
Grandle使用同樣運(yùn)行于JVM上的Groovy語(yǔ)言編寫,本文會(huì)對(duì)此進(jìn)行初步夠用的講解,接下來(lái)我們就一起來(lái)看一下Java使用自動(dòng)化部署工具Gradle中的任務(wù)設(shè)定教程:

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

 task myTask {
 println "Hello, World!"
 }

 task myTask {
 doLast {
 println "Hello, World!"
 }
 }

 task myTask << {
 println "Hello, World!"
 }

我的目的是創(chuàng)建一個(gè)task,當(dāng)它執(zhí)行的時(shí)候會(huì)打印出來(lái)”Hello, World!”。當(dāng)我第一次創(chuàng)建task的時(shí)候,我猜測(cè)應(yīng)該是這樣來(lái)寫的:

 task myTask {
 println "Hello, World!"
 }

現(xiàn)在,試著來(lái)執(zhí)行這個(gè)myTask,在命令行輸入gradle myTask,打印如下:

 user$ gradle myTask
 Hello, World!
 :myTask UP-TO-DATE

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

 user$ gradle tasks
 Hello, World!
 :tasks

 ------------------------------------------------------------
 All tasks runnable from root project
 ------------------------------------------------------------

 Build Setup tasks
 -----------------
 init - Initializes a new Gradle build. [incubating]
 ..........

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

Gradle在執(zhí)行task之前都要對(duì)task先進(jìn)行配置。那么問(wèn)題就來(lái)了,我怎么知道我的task中,哪些代碼是在配置過(guò)程中執(zhí)行的,哪些代碼是在task執(zhí)行的時(shí)候運(yùn)行的?答案就是,在task的最頂層的代碼就是配置代碼,比如:

 task myTask {
 def name = "Pavel" //<-- 這行代碼會(huì)在配置階段執(zhí)行
 println "Hello, World!"http:////<-- 這行代碼也將在配置階段執(zhí)行
 }

這就是為什么我執(zhí)行g(shù)radle tasks的時(shí)候,會(huì)打印出來(lái)”Hello, World!”-因?yàn)榕渲么a被執(zhí)行了。但這并不是我想要的效果,我想要”Hello, World!”僅僅在我顯式的調(diào)用myTask的時(shí)候才打印出來(lái)。為了達(dá)到這個(gè)效果,最簡(jiǎn)單的方法就是就是使用Task#doLast()方法。

 task myTask {
 def text = 'Hello, World!' //configure my task
 doLast {
 println text //this is executed when my task is called
 }
 }

現(xiàn)在,”Hello, World!”僅僅會(huì)在我執(zhí)行g(shù)radle myTask的時(shí)候打印出來(lái)。Cool,現(xiàn)在我已經(jīng)知道如何配置以及使task做正確的事情。還有一個(gè)問(wèn)題,最開(kāi)始的例子中,第三個(gè)task的<<符號(hào)是什么意思?

 task myTask2 << {
 println "Hello, World!" 
 }

這其實(shí)只是doLast的一個(gè)語(yǔ)法糖版本。它和下面的寫法效果是一樣的:

 task myTask {
 doLast {
 println 'Hello, World!' //this is executed when my task is called
 }
 }

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

語(yǔ)法

Gradle腳本是使用Groovy語(yǔ)言來(lái)寫的。Groovy的語(yǔ)法有點(diǎn)像Java,希望你能接受它。
如果你對(duì)Groovy已經(jīng)很熟悉了,可以跳過(guò)這部分了。
Groovy中有一個(gè)很重要的概念你必要要弄懂–Closure(閉包)

Closures

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

關(guān)鍵是這塊代碼會(huì)在你調(diào)用的時(shí)候執(zhí)行,而不是在創(chuàng)建的時(shí)候。看一個(gè)Closure的例子:

def myClosure = { println 'Hello world!' }

//execute our closure
myClosure()

#output: Hello world!

下面是一個(gè)接收參數(shù)的Closure:

def myClosure = {String str -> println str }

//execute our closure
myClosure('Hello world!')

#output: Hello world!

如果Closure只接收一個(gè)參數(shù),可以使用it來(lái)引用這個(gè)參數(shù):

def myClosure = {println it }

//execute our closure
myClosure('Hello world!')

#output: Hello world!

接收多個(gè)參數(shù)的Closure:

def myClosure = {String str, int num -> println "$str : $num" }

//execute our closure
myClosure('my string', 21)

#output: my string : 21

另外,參數(shù)的類型是可選的,上面的例子可以簡(jiǎn)寫成這樣:

def myClosure = {str, num -> println "$str : $num" }

//execute our closure
myClosure('my string', 21)

#output: my string : 21

很酷的是Closure中可以使用當(dāng)前上下文中的變量。默認(rèn)情況下,當(dāng)前的上下文就是closure被創(chuàng)建時(shí)所在的類:

def myVar = 'Hello World!'
def myClosure = {println myVar}
myClosure()

#output: Hello world!

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

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!

正如你鎖看見(jiàn)的,在創(chuàng)建closure的時(shí)候,myVar并不存在。這并沒(méi)有什么問(wèn)題,因?yàn)楫?dāng)我們執(zhí)行closure的時(shí)候,在closure的上下文中,myVar是存在的。這個(gè)例子中。因?yàn)槲以趫?zhí)行closure之前改變了它的上下文為m,因此myVar是存在的。

把closure當(dāng)做參數(shù)傳遞

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

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

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

Gradle例子

現(xiàn)在我們已經(jīng)了解了基本的語(yǔ)法了,那么如何在Gradle腳本中使用呢?先看下面的例子吧:

buildscript {
 repositories {
 jcenter()
 }
 dependencies {
 classpath 'com.android.tools.build:gradle:1.2.3'
 }
}

allprojects {
 repositories {
 jcenter()
 }
}

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

def buildscript(Closure closure)

接著是allprojects方法,它也接收一個(gè)closure參數(shù):

   

def allprojects(Closure closure)

其他的都類似。。。

現(xiàn)在看起來(lái)容易多了,但是還有一點(diǎn)不明白,那就是這些方法是在哪里定義的?答案就是Project

Project

這是理解Gradle腳本的一個(gè)關(guān)鍵。

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

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

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

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

Script blocks

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

android Script block

我們來(lái)看看默認(rèn)的Android app/build.gradle文件:

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的時(shí)候遇到的大多數(shù)問(wèn)題都是和task的執(zhí)行順序有關(guān)的。很明顯如果我的構(gòu)建會(huì)工作的更好如果我的task都是在正確的時(shí)候執(zhí)行。下面我們就深入了解一下如何更改task的執(zhí)行順序。

dependsOn

我認(rèn)為最直接的方式來(lái)說(shuō)明的你task的執(zhí)行時(shí)依賴別的task的方法就是使用dependsOn方法。
比如下面的場(chǎng)景,已經(jīng)存在task A,我們要添加一個(gè)task B,它的執(zhí)行必須要在A執(zhí)行完之后:

2016618164000436.png (394×164)

這是一個(gè)很簡(jiǎn)單的場(chǎng)景,假定A和B的定義如下:

task A << {println 'Hello from A'}
task B << {println 'Hello from B'}

只需要簡(jiǎn)單的調(diào)用B.dependsOn A,就可以了。
這意味著,只要我執(zhí)行task B,task A都會(huì)先執(zhí)行。

paveldudka$ gradle B
:A
Hello from A
:B
Hello from B

另外,你也可以在task的配置區(qū)中來(lái)聲明它的依賴:

task A << {println 'Hello from A'}
task B {
 dependsOn A
 doLast {
 println 'Hello from B' 
 }
}

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

2016618164044136.png (583×359)

過(guò)程和剛才類似。假定已經(jīng)存在如下的task依賴:

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

task B1 << {println 'Hello from B1'}
B1.dependsOn B
C.dependsOn B1

輸出:

paveldudka$ gradle C
:A
Hello from A
:B
Hello from B
:B1
Hello from B1
:C
Hello from C

注意dependsOn把task添加到依賴的集合中,所以依賴多個(gè)task是沒(méi)有問(wèn)題的。

2016618164255177.png (541×262)                                   

task B1 << {println 'Hello from B1'}
B1.dependsOn B
B1.dependsOn Q

輸出:

paveldudka$ gradle B1
:A
Hello from A
:B
Hello from B
:Q
Hello from Q
:B1
Hello from B1

mustRunAfter

現(xiàn)在假定我又一個(gè)task,它依賴于其他兩個(gè)task。這里我使用一個(gè)真實(shí)的場(chǎng)景,我有兩個(gè)task,一個(gè)單元測(cè)試的task,一個(gè)是UI測(cè)試的task。另外還有一個(gè)task是跑所有的測(cè)試的,它依賴于前面的兩個(gè)task。

2016618164352331.png (470×169)

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

輸出:

paveldudka$ gradle tests
:ui
Hello from UI tests
:unit
Hello from unit tests
:tests
Hello from all tests!

盡管unitest和UI test會(huì)子啊test task之前執(zhí)行,但是unit和ui這兩個(gè)task的執(zhí)行順序是不能保證的。雖然現(xiàn)在來(lái)看是按照字母表的順序執(zhí)行,但這是依賴于Gradle的實(shí)現(xiàn)的,你的代碼中絕對(duì)不能依賴這種順序。
由于UI測(cè)試時(shí)間遠(yuǎn)比unit test時(shí)間長(zhǎng),因此我希望unit test先執(zhí)行。一個(gè)解決辦法就是讓ui task依賴于unit task。

2016618164602490.png (474×256)

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

輸出:

paveldudka$ gradle tests
:unit
Hello from unit tests
:ui
Hello from UI tests
:tests
Hello from all tests!

現(xiàn)在unit test會(huì)在ui test之前執(zhí)行了。
但是這里有個(gè)很惡心的問(wèn)題,我的ui測(cè)試其實(shí)并不依賴于unit test。我希望能夠單獨(dú)的執(zhí)行ui test,但是這里每次我執(zhí)行ui test,都會(huì)先執(zhí)行unit test。
這里就要用到mustRunAfter了。mustRunAfter并不會(huì)添加依賴,它只是告訴Gradle執(zhí)行的優(yōu)先級(jí)如果兩個(gè)task同時(shí)存在。比如我們這里就可以指定ui.mustRunAfter unit,這樣如果ui task和unit task同時(shí)存在,Gradle會(huì)先執(zhí)行unit test,而如果只執(zhí)行g(shù)radle ui,并不會(huì)去執(zhí)行unit task。

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

輸出:

paveldudka$ gradle tests
:unit
Hello from unit tests
:ui
Hello from UI tests
:tests
Hello from all tests!

依賴關(guān)系如下圖:

2016618164643195.png (474×256)

mustRunAfter在Gradle2.4中目前還是實(shí)驗(yàn)性的功能。
finalizedBy

現(xiàn)在我們已經(jīng)有兩個(gè)task,unit和ui,假定這兩個(gè)task都會(huì)輸出測(cè)試報(bào)告,現(xiàn)在我想把這兩個(gè)測(cè)試報(bào)告合并成一個(gè):

2016618164702504.png (474×375)

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

現(xiàn)在如果我想獲得ui和unit的測(cè)試報(bào)告,執(zhí)行task mergeReports就可以了。

paveldudka$ gradle mergeReports
:unit
Hello from unit tests
:ui
Hello from UI tests
:tests
Hello from all tests!
:mergeReports
Merging test reports

這個(gè)task是能工作,但是看起來(lái)好笨啊。mergeReports從用戶的角度來(lái)看感覺(jué)不是特別好。我希望執(zhí)行tests task就可以獲得測(cè)試報(bào)告,而不必知道m(xù)ergeReports的存在。當(dāng)然我可以把merge的邏輯挪到tests task中,但我不想把tests task搞的太臃腫,我還是繼續(xù)把merge的邏輯放在mergeReports task中。
finalizeBy來(lái)救場(chǎng)了。顧名思義,finalizeBy就是在task執(zhí)行完之后要執(zhí)行的task。修改我們的腳本如下:

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

現(xiàn)在執(zhí)行tests task就可以拿到測(cè)試報(bào)告了:

paveldudka$ gradle tests
:unit
Hello from unit tests
:ui
Hello from UI tests
:tests
Hello from all tests!
:mergeReports
Merging test reports

相關(guān)文章

  • Java Integer對(duì)象的比較方式

    Java Integer對(duì)象的比較方式

    這篇文章主要介紹了Java Integer對(duì)象的比較方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java詳細(xì)分析Lambda表達(dá)式與Stream流的使用方法

    Java詳細(xì)分析Lambda表達(dá)式與Stream流的使用方法

    Lambda表達(dá)式,基于Lambda所帶來(lái)的函數(shù)式編程,又引入了一個(gè)全新的Stream概念,用于解決集合類庫(kù)既有的弊端,Lambda 允許把函數(shù)作為一個(gè)方法的參數(shù)(函數(shù)作為參數(shù)傳遞進(jìn)方法中)。使用 Lambda 表達(dá)式可以使代碼變的更加簡(jiǎn)潔緊湊
    2022-04-04
  • 基于Properties類操作.properties配置文件方法總結(jié)

    基于Properties類操作.properties配置文件方法總結(jié)

    這篇文章主要介紹了Properties類操作.properties配置文件方法總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • JSONObject按put順序排放與輸出方式

    JSONObject按put順序排放與輸出方式

    這篇文章主要介紹了JSONObject按put順序排放與輸出方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 使用Flyway進(jìn)行Java數(shù)據(jù)庫(kù)版本控制的操作指南

    使用Flyway進(jìn)行Java數(shù)據(jù)庫(kù)版本控制的操作指南

    今天我們將深入探討如何使用Flyway進(jìn)行Java數(shù)據(jù)庫(kù)版本控制,Flyway是一個(gè)流行的數(shù)據(jù)庫(kù)遷移工具,用于管理和自動(dòng)化數(shù)據(jù)庫(kù)模式的演變,文中通過(guò)代碼示例介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-07-07
  • Java實(shí)現(xiàn)租車管理系統(tǒng)

    Java實(shí)現(xiàn)租車管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)租車管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • 新版idea工具欄菜單展開(kāi)與合并顯示方式

    新版idea工具欄菜單展開(kāi)與合并顯示方式

    文章介紹了如何在新版IDEA中調(diào)整工具欄菜單的顯示方式,通過(guò)取消勾選設(shè)置中的某個(gè)選項(xiàng),可以使菜單展開(kāi)更加方便
    2025-01-01
  • java+jsp+struts2實(shí)現(xiàn)發(fā)送郵件功能

    java+jsp+struts2實(shí)現(xiàn)發(fā)送郵件功能

    這篇文章主要為大家詳細(xì)介紹了java+jsp+struts2實(shí)現(xiàn)發(fā)送郵件功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • idea配置SVN的教程

    idea配置SVN的教程

    文章介紹了如何安裝和配置TortoiseSVN以及在IntelliJ?IDEA中配置SVN,首先,安裝TortoiseSVN時(shí)需要選擇與電腦配置相匹配的版本,并確保安裝命令行客戶端工具,其次,在IntelliJ?IDEA中配置SVN時(shí),需要指定SVN可執(zhí)行文件的路徑
    2025-01-01
  • Java函數(shù)式編程(一):你好,Lambda表達(dá)式

    Java函數(shù)式編程(一):你好,Lambda表達(dá)式

    這篇文章主要介紹了Java函數(shù)式編程(一):你好,Lambda表達(dá)式,本文講解了新老函數(shù)式編程的一些變化,需要的朋友可以參考下
    2014-09-09

最新評(píng)論

中西区| 马关县| 边坝县| 陆河县| 汝城县| 台湾省| 固阳县| 同仁县| 乳山市| 武城县| 柘荣县| 贡山| 旺苍县| 洱源县| 中西区| 张家口市| 夹江县| 扎赉特旗| 将乐县| 荃湾区| 上思县| 云林县| 鹤岗市| 汝州市| 安龙县| 临猗县| 长兴县| 安阳市| 琼中| 徐州市| 西林县| 泗阳县| 莒南县| 阳江市| 三亚市| 南江县| 阳谷县| 团风县| 威信县| 乳山市| 金塔县|