Gradle深刻與實戰(轉)

轉自:NO END FOR LEARNING http://benweizhu.github.io/blog/2015/01/31/deep-into-gradle-in-action-1/

什麼是構建工具?

一個可編程的工具,可以以可執行和有序的任務來表達知足須要的自動化過程。html

以Java爲例,要獲得一個簡單可運行的Jar文件,須要下面幾步:前端

1.編譯源代碼
2.運行測試(前提是你有測試) 3.拷貝Class文件到目標目錄
4.打包Class文件爲Jar文件java

這是一個完整的可自動化的過程,在沒有構建工具以前,是由誰來作?IDE。一個強大的IDE,以上的步驟都只須要按幾個按鈕,這讓開發人員的生活變得很美好,徹底集中在寫出優秀的代碼。python

如今,原本整個開發過程只須要你一我的,隨着任務的難度和複雜度的加重,你的團隊從一我的變成了3我的或者更多。這時,你確定會須要代碼集成,這個問題好解決,使用版本控制,不管是中心式的SVN仍是分佈式的Git,總之能夠既能夠解決版本問題,也解決代碼集成的問題。git

這種狀況下,在沒有自動化構建時,你確定會遇到下面幾個問題: 
1.在個人機器上能夠跑 
2.從版本控制check out代碼,發現編譯不過,有人少提交了代碼文件
3.有我的提交代碼時沒跑測試,致使其餘人check out代碼後,測試跑不過
4.版本發佈時,由一我的來check out全部代碼,在他本身的機器上編譯打包,結果部署到服務器上運行不了
github

致使上面這些問題出現的緣由都有兩個特色: 
1.手動介入
2.重複任務web

開發人員要關注的應該是編寫實現功能的代碼,至於編譯編譯代碼,拷貝文件,運行測試等一切重複和可自動化的事情都應該交給機器去作,由於人是容易犯錯的。編程

Java世界的構建工具

在Java的世界裏,目前在被使用的經常使用構建工具備三個:Ant,Maven,Gradle。api

Ant的核心是由Java編寫,採用XML做爲構建腳本,這樣就容許你在任何環境下,運行構建。Ant基於任務鏈思想,任務之間定義依賴,造成前後順序。缺點是使用XML定義構建腳本,致使腳本臃腫,Ant自身沒有爲項目構建提供指導,致使每一個build腳本都不同,開發人員對於每一個項目都須要去熟悉腳本內容,沒有提供在Ant生態環境內的依賴管理工具。緩存

Maven團隊意識到Ant的缺陷,採用標準的項目佈局,和統一的生命週期,採用約定因爲配置的思想,減小構建腳本須要的編寫內容,活躍的社區,能夠方便找到合適的插件,強大的依賴管理工具。缺點是採用默認的結構和生命週期,太過限制,編寫插件擴展麻煩,XML做爲構建腳本。

若是有一個構建工具能夠折中,同時擁有Ant和Maven的優勢,是否是很爽?告訴你有,那就是Gradle。

Gradle

基於Groovy的DSL,提供聲明式的構建語言 
採用標準的項目佈局,但擁有徹底的可配置性,就是能夠改 
經過插件,提供默認的構建生命週期,也能夠本身定義任務,單獨運行任務,定義任務間的依賴 
強大的依賴管理工具,與Maven和Ivy倉庫結合
與Ant天生兼容,有效的重用Ant的任務
多種實現插件的方式,強大的官方插件庫
從構建級別,支持從Ant或者Maven的逐步遷移
經過包裝器,無縫的在各個平臺運行

看一個超級簡單的例子:

若是你的項目採用標準的Maven佈局(Java世界的標準佈局)

1
2 3 4 5 6 7 8 9 10 
src {//目錄結構而已,不是代碼  main {  java  resources  }  test {  java  resources  } } 

在項目根目錄下,建立一個build.gradle,這個是Gradle的構建腳本文件,就和build.xml,POM.xml道理同樣。

那麼你要實現Java的編譯,測試,拷貝class到目標目錄,打包Jar文件等,只須要在構建腳本中,使用下面一句話,使用Java插件。

1
apply plugin: 'java' 

而後運行gradle build。

下一篇,咱們深刻到實戰學習Java插件的使用和依賴管理,讓你快速開始Java應用開發。

沒有介紹Gradle的基礎知識,直接開始實戰,目的是爲了更快的讓你們開始使用Gradle作構建,快速上手,當須要實現的自動化需求更復雜時,在深刻學習基礎知識。

這一篇,咱們直接開始Java插件的使用。

應用Java插件

Gradle是一個通用構建工具,也就是說,它不單是爲Java而生。好比,還能夠作Groovy,Scala的構建。這取決於你使用什麼樣的插件。

大部分Java項目的基本步驟都很是相似,編譯Java源代碼,運行單元測試,拷貝生成的class文件到目標目錄,打包Jar文件(或者War包,Ear包),而這些重複且約定俗成的任務,若是能夠不用寫一行構建代碼就實現,是多麼的棒!Maven就作到這一點,採用約定因爲配置的思想,預先定義經常使用的任務,並定義它們的執行順序。

Gradle吸取了Maven的這個優勢,經過插件,實現預約義任務和任務之間依賴關係的導入,這樣就能夠在一行代碼都不寫的狀況下(若是應用插件,你以爲也算一行的話,那就寫一行吧),直接使用已經定義的任務。

1
apply plugin: 'java' 

SourceSet和項目佈局

就和Maven同樣,在默認的狀況下,項目的目錄結構是固定的Java世界的標準項目目錄佈局,只不過Maven的不能夠改,可是Gradle能夠改。

1
2 3 4 5 6 7 8 9 10 
src {//目錄結構而已,不是代碼  main {  java  resources  }  test {  java  resources  } } 

Java插件引入了一個概念叫作SourceSets,它表明了一組源文件,經過修改SourceSets中的屬性,能夠指定哪些源文件(或文件夾下的源文件)要被編譯,哪些源文件要被排除。Gradle就是經過它實現Java項目的佈局定義。

Java插件默認實現了兩個SourceSet,main和test。每一個SourceSet都提供了一系列的屬性,經過這些屬性,能夠定義該SourceSet所包含的源文件。好比,java.srcDirs,resources.srcDirs。Java插件中定義的其餘任務,就根據main和test的這兩個SourceSet的定義來尋找產品代碼和測試代碼等。

在構建腳本中,怎麼樣定義或者修改SourceSet呢?Gradle提供了一系列的DSL,可讓你方便的定義或者修改配置。好比,sourceSets的DSL。

1
2 3 4 5 6 7 8 9 10 
sourceSets {  main {  java {  srcDir 'src/java'  }  resources {  srcDir 'src/resources'  }  } } 

上面的這個例子,在sourceSets中,修改了Java插件中已經定義的SourceSet main,修改了它的java.srcDir和resources.srcDir。因而,項目的目錄結構就改變了。

改變Java插件中預約義的項目目錄結構,不是咱們最終的目的,由於它是目前Java世界,標準的項目佈局,或者說你們都遵照的項目佈局。

sourceSets最主要的做用是增長新的目錄約定,好比,你想要定義一個新的SourceSet來管理集成測試的源文件,這樣能夠將單元測試和集成測試分開管理。

至於,關於具體如何爲集成測試寫一個新的SourceSet會在後面介紹依賴管理時舉例說明。

Java插件提供的任務

Java插件提供了一系列的任務給你使用,包括編譯,運行測試,打包等等。當你在項目中應用Java插件時,就已經將這些任務集成到你的項目中了。

在命令行中,運行gradle tasks命令,能夠查看當前項目下主要的task。

1
2 3 4 5 6 7 8 9 10 11 12 13 14 
Build tasks assemble - Assembles the outputs of this project. build - Assembles and tests this project. buildDependents - Assembles and tests this project and all projects that depend on it. buildNeeded - Assembles and tests this project and all projects it depends on. clean - Deletes the build directory. jar - Assembles a jar archive containing the main classes.  Documentation tasks javadoc - Generates Javadoc API documentation for the main source code.  Verification tasks check - Runs all checks. test - Runs the unit tests. 

你能夠對比Java插件應用前和應用後該命令的輸出,Java插件提供的任務有不少,至於每一個任務是作什麼,這裏就不贅述了。

Java插件除了爲你預約義這些任務,該預約義了這些任務之間的依賴關係。以下圖:

你也能夠經過命令gradle tasks –all來查看每一個task各自有什麼依賴。

固然,這裏仍是重點提下,Java插件中四個重要和經常使用的任務,assemble,check,build,clean。

assemble 
All archive tasks in the project, including jar. Some plugins add additional archive tasks to the project. 
check 
All verification tasks in the project, including test. Some plugins add additional verification tasks to the project. 
build 
check and assemble 
clean 
Deletes the project build directory.

assemble被用來產生Jar文件,輸出目錄在build/libs下。

check用來運行全部的驗收任務,包括test任務,以及其餘驗收任務,好比checkstyle。

Tips:在命令行中運行單個測試

JAVA插件中的test任務提供了一個filter屬性,能夠幫助指定運行test任務時,什麼測試源文件要包含,什麼要排除。

1
2 3 4 5 6 7 8 9 10 11 12 
test {  filter {  //include specific method in any of the tests  includeTestsMatching "*UiCheck"   //include all tests from package  includeTestsMatching "org.gradle.internal.*"   //include all integration tests  includeTestsMatching "*IntegTest"  } } 

固然通常狀況下,你不會這麼去作。

但重點是,你能夠經過命令行傳遞的參數來指定這個matching規則,這樣你就能夠經過命令行來指定跑某一類測試,或者單個測試。你必定遇到過,某個測試在命令行中能夠運行,在IDE中不能運行,或者反過來。這時,你能夠不會想要跑所有的測試來驗證某一個測試。因而,你就能夠經過命令行來運行某一個測試:

1
2 
gradle test --tests org.gradle.SomeTest.someSpecificFeature gradle test --tests *IntegTest 

到目前爲止,你已經瞭解了Java插件提供的一些核心功能和有用小技巧。雖然還未涉及到Jar任務和uploadfile任務(這些任務當須要時,再去看就好了),可是就啓動項目而言,對Java插件的使用所須要瞭解的知識已經足夠了。

下一節,講解依賴管理

大部分的項目都不是自包含的,也就是說,須要使用到其餘項目的構建結果,好比一些Jar文件。它們做爲輸入文件,必須存在於項目的ClassPath下,程序才能編譯和運行。這些輸入文件有一個很表意的名字,叫作依賴。

Gradle容許你告訴它項目的依賴是什麼,而後它就會負責找到這些依賴。這些依賴會從Maven或者Ivy的遠程倉庫下載下來(大部分狀況),並緩存在本地的某個路徑,這個過程叫作依賴解析。

Maven和Gradle同樣也提供了相似的功能,而Ant沒有,你只能告訴Ant依賴文件的相對或者絕對路徑,讓它去加載。

經常一個依賴本身也存在依賴,咱們稱爲傳遞依賴,依賴管理工具又具備解析傳遞依賴的能力。

Gradle的依賴管理

那麼如何在Gradle中定義依賴呢?看個最簡單的例子。

1
2 3 4 5 6 7 8 9 
apply plugin: 'java'  repositories {  mavenCentral() }  dependencies {  testCompile 'junit:junit:4.11'// testCompile group: 'junit', name: 'junit', version: '4.11' } 

項目使用了Java的插件,在repositories塊中告訴Gradle使用maven的遠程倉庫做爲依賴下載地址,在dependencies塊定義了一個junit的依賴,並說明了分組(Maven中的Scope),後面註釋中有一個表意更完整的依賴定義,說明了依賴聲明使用的三個座標group,name,version。

整個看起來是那麼的表意,使用過Maven更會以爲是無縫轉換,甚至更簡潔。

Dependency configurations 依賴分組

在Gradle中,依賴都被會分配到某一個具體的configuration中(這裏我不傾向於翻譯成配置,我以爲佈局,或者分組更適合)。Configuration表明着一個或多個構件及構件所需依賴的一個分組。

Java插件已經預約義了一些configuration,好比,compile,runtime,testCompile,testRuntime等。

compile 放在這個configuration下的依賴是在編譯產品代碼時所使用的,但它做爲一個分組,包含產品代碼和編譯所需的依賴。 
runtime 產品代碼在運行時須要的依賴,默認,也會包含compile中的依賴。 
testCompile 編譯測試代碼時所須要的依賴,默認,被編譯的產品代碼和產品代碼須要的編譯依賴也屬於該分組。 
testRuntime 運行測試時須要的依賴。默認,包含compile,runtime和testCompile的分組的構建和依賴。

使用過Maven的都應該知道分組的含義,這裏講解給不明白的同窗,依賴之因此要分組,是由於,每一個階段對依賴的須要不同,最明顯的是產品代碼和測試代碼,好比junit在產品代碼中就不須要。

那麼,爲何產品代碼的編譯階段和運行階段也分組,通常編譯階段須要的依賴,在運行階段也須要,可是反過來就不必定了。好比,你經過反射去load一個class,這時該class就不必定須要在編譯階段存在。

一個更常見的例子,作web開發時須要servlet的依賴,可是隻是編譯階段,運行時servlet依賴由servlet容器來提供。因此Gradle的War插件也提供了兩個configuration,分別是providedCompile和providedRuntime,它們對依賴的使用範圍定義和compile以及runtime一致,只不過依賴的Jar包不會被加到War包裏面。

定義SourceSet時,添加的Configuration

上一節,在介紹Java插件的時候,提到了SourceSet概念。針對每個新添加的SourceSet,Java插件都會動態的給它添加兩個Configuration,分別是sourceSetCompile和sourceSetRuntime。

好比:新添加一個SourceSet,叫作int,那麼對應的Configuration是intCompile和intRuntime。

這一特性也正好印證,Java插件是如何識別自定義SourceSet來進行編譯和運行。

依賴的多種定義方式

除了經過遠程倉庫和依賴座標來定義依賴,Gradle還提供了另外兩種經常使用的依賴定義方式,對本地文件的依賴,對某個項目的依賴。

對文件的依賴

這種狀況看起來是否是很奇葩,都有依賴管理了和Maven倉庫了還要什麼文件依賴。其實否則,使用這種定義方式,最多見場景是項目構建工具的遷移,從Ant到Gradle。不管任何項目,遷移過程都是小步前進,Gradle提供文件依賴的配置,就是爲了解決這些特殊性。

1
2 3 4 
dependencies {  runtime files('libs/a.jar', 'libs/b.jar')  runtime fileTree(dir: 'libs', include: '*.jar') } 

對另外一個工程的依賴

項目中劃分子模塊是很日常的事情,前端Controller和數據層Dao分離管理就是一個例子,那麼在進行前端Controller模塊構建時,就須要將數據層模塊做爲依賴。定義方式以下:

1
2 3 
dependencies {  compile project(':shared') } 

依賴版本衝突

依賴衝突是因此依賴管理中最頭痛的問題,這經常出如今傳遞依賴中。Gradle對解決傳遞依賴提供了兩種策略,使用最新版本或者直接致使構建失敗。默認的策略是使用最新版本。雖然這樣的策略可以解決一些問題,可是仍是不夠。常見的一種狀況是,NoSuchMethond或者ClassNotFound。這時候,你可能須要一些特殊手段,好比排除不想要的傳遞依賴。

排除傳遞依賴

排除傳遞依賴有多種緣由,遠程倉庫中不存在,運行時不須要,或者版本衝突。排除傳遞依賴的方式有兩種:1.直接在configuration中排除 2.在具體的某個dependency中排除

1
2 3 4 5 6 7 8 9 10 
configurations {  compile.exclude module: 'commons'  all*.exclude group: 'org.gradle.test.excludes', module: 'reports' }  dependencies {  compile("org.gradle.test.excludes:api:1.0") {  exclude module: 'shared'  } } 

經過命令行查看依賴關係

當出現依賴衝突時,最主要的仍是要分析依賴衝突的緣由,Gradle提供了兩個任務來幫助你分析依賴關係

dependencies - Displays all dependencies declared in root project ‘projectReports’. 
dependencyInsight - Displays the insight into a specific dependency in root project ‘projectReports’.

Tips:輸出依賴關係圖到文件

在命令行中直接使用gradle dependencies能夠打印出依賴圖,可是在命令行中查看始終不太方便,咱們能夠將結果輸出到一個文件中,以下:

1
gradle dependencies > dependencies.txt 

dependencies.txt保存在項目的根目錄

Gradle的官方文檔中關於Gradle的依賴管理的內容還有不少,好比,如何訪問須要用戶名密碼受權的Maven倉庫等等。等多內容,能夠參考官方文檔:http://gradle.org/docs/current/userguide/dependency_management.html

下一節,利用前三節學到的知識,編寫集成測試任務,並單獨劃分SourceSet。

相關文章
相關標籤/搜索