程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java應用主動化安排對象Gradle中的義務設定教程

Java應用主動化安排對象Gradle中的義務設定教程

編輯:關於JAVA

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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved