Java應用主動化安排對象Gradle中的義務設定教程。本站提示廣大學習愛好者:(Java應用主動化安排對象Gradle中的義務設定教程)文章只能為提供參考,不一定能成為您想要的結果。以下是Java應用主動化安排對象Gradle中的義務設定教程正文
tasks
上面的代碼展現了三個Gradle task,稍後會講授這三者的分歧。
task myTask { println "Hello, World!" } task myTask { doLast { println "Hello, World!" } } task myTask << { println "Hello, World!" }
我的目標是創立一個task,當它履行的時刻會打印出來”Hello, World!”。當我第一次創立task的時刻,我猜想應當是如許來寫的:
task myTask { println "Hello, World!" }
如今,試著來履行這個myTask,在敕令行輸出gradle myTask,打印以下:
user$ gradle myTask Hello, World! :myTask UP-TO-DATE
這個task看起來起感化了。它打印了”Hello, World!”。
然則,它其實並沒有像我們希冀的那樣。上面我們來看看為何。在敕令行輸出gradle tasks來檢查一切可用的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!”打印出來了?我只是想看看有哪些可用的task,並沒有履行任何自界說的task!
緣由其實很簡略,Gradle task在它的性命周期中有兩個重要的階段:設置裝備擺設階段 和 履行階段。
能夠我的用詞不是很准確,但這切實其實能贊助我懂得tasks。
Gradle在履行task之前都要對task先輩行設置裝備擺設。那末成績就來了,我怎樣曉得我的task中,哪些代碼是在設置裝備擺設進程中履行的,哪些代碼是在task履行的時刻運轉的?謎底就是,在task的最頂層的代碼就是設置裝備擺設代碼,好比:
task myTask { def name = "Pavel" //<-- 這行代碼會在設置裝備擺設階段履行 println "Hello, World!"////<-- 這行代碼也將在設置裝備擺設階段履行 }
這就是為何我履行gradle tasks的時刻,會打印出來”Hello, World!”-由於設置裝備擺設代碼被履行了。但這其實不是我想要的後果,我想要”Hello, World!”僅僅在我顯式的挪用myTask的時刻才打印出來。為了到達這個後果,最簡略的辦法就是就是應用Task#doLast()辦法。
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的<<符號是甚麼意思?
task myTask2 << { println "Hello, World!" }
這其實只是doLast的一個語法糖版本。它和上面的寫法後果是一樣的:
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的例子:
def myClosure = { println 'Hello world!' } //execute our closure myClosure() #output: Hello world!
上面是一個吸收參數的Closure:
def myClosure = {String str -> println str } //execute our closure myClosure('Hello world!') #output: Hello world!
假如Closure只吸收一個參數,可使用it來援用這個參數:
def myClosure = {println it } //execute our closure myClosure('Hello world!') #output: Hello world!
吸收多個參數的Closure:
def myClosure = {String str, int num -> println "$str : $num" } //execute our closure myClosure('my string', 21) #output: my string : 21
別的,參數的類型是可選的,下面的例子可以簡寫成如許:
def myClosure = {str, num -> println "$str : $num" } //execute our closure myClosure('my string', 21) #output: my string : 21
很酷的是Closure中可使用以後高低文中的變量。默許情形下,以後的高低文就是closure被創立時地點的類:
def myVar = 'Hello World!' def myClosure = {println myVar} myClosure() #output: Hello world!
別的一個很酷的點是closure的高低文是可以轉變的,經由過程Closure#setDelegate()。這個特征異常有效:
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劇本中應用呢?先看上面的例子吧:
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.2.3' } } allprojects { repositories { jcenter() } }
曉得了Groovy的語法,是否是下面的例子就很好懂得了?
起首就是一個buildscript辦法,它吸收一個closure:
def buildscript(Closure closure)
接著是allprojects辦法,它也吸收一個closure參數:
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文件:
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履行完以後:
這是一個很簡略的場景,假定A和B的界說以下:
task A << {println 'Hello from A'} task B << {println 'Hello from B'}
只須要簡略的挪用B.dependsOn A,便可以了。
這意味著,只需我履行task B,task A都邑先履行。
paveldudka$ gradle B :A Hello from A :B Hello from B
別的,你也能夠在task的設置裝備擺設區中來聲明它的依附:
task A << {println 'Hello from A'} task B { dependsOn A doLast { println 'Hello from B' } }
假如我們想要在曾經存在的task依附中拔出我們的task該怎樣做呢?
進程和適才相似。假定曾經存在以下的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添加到依附的聚集中,所以依附多個task是沒有成績的。
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
如今假定我又一個task,它依附於其他兩個task。這裡我應用一個真實的場景,我有兩個task,一個單位測試的task,一個是UI測試的task。別的還有一個task是跑一切的測試的,它依附於後面的兩個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
輸入:
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。
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!
如今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。
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!
依附關系以下圖:
mustRunAfter在Gradle2.4中今朝照樣試驗性的功效。
finalizedBy
如今我們曾經有兩個task,unit和ui,假定這兩個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
如今假如我想取得ui和unit的測試申報,履行task mergeReports便可以了。
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。修正我們的劇本以下:
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便可以拿到測試申報了:
paveldudka$ gradle tests :unit Hello from unit tests :ui Hello from UI tests :tests Hello from all tests! :mergeReports Merging test reports