簡介:構建系統時候常常要用到 Ant, Maven 等工具,對於初學者來說,它們還是過於復雜,上手還 是需要時間的。本文將向讀者介紹一種全新的構建項目的方式 gradle,它簡單、上手快,能大大節省項 目的時間和成本。
在 eclipse 下利用 gradle 構建系統
基本開發環境
操作系統:本教程使用的為 Windows Vista Enterprise, 如果您的系統是 Linux 的,請選擇下載對 應版本的其他工具,包括開發工具、Java EE 服務器、Apache Ant、SoapUI。
開發工具:Eclipse IDE for SOA Developers 版本,請到 http://www.eclipse.org/downloads/ 網 站下載,當然任何版本的 eclipse 都是可以的。
Java EE 服務器:Apache-Tomcat-6.0.18,可以到 http://tomcat.apache.org/download-60.cgi 下 載,使用 5.0 以上的任何版本都可以的,當然,您也可以使用 Jboss 等其他 Java EE 服務器。
Jdk:到 http://java.sun.com 下載 1.5.0_17 版本,下載後安裝即可。
Ant,Maven,Gradle 簡單比較
Ant 是我們過去構建系統基本都會用到的,xml 腳本文件中包括若干 task 任務,任務之間可以互相 依賴,對於一個大的項目來說,這些 xml 文件維護起來的確不是一件容易的事情,還有那些項目依賴的 而沒有版本號的 jar 包,有時真的讓人頭疼,後來 Maven 出現了,基於中央倉庫的編譯相對於 Ant 來 說的確是好了很多,但是,是不是 Ant,Maven 就是我們構建項目的唯一選擇呢?呵呵,當然不了,利用 Gradle 來構建系統我認為將成為 java 構建項目的最佳選擇,簡單,快速,對初學者無苛刻要求,可以 說是拿來就會用,而且我們再也不用看那些冗長而復雜的 xml 文件了,因為 Gradle 是基於 Groovy 語 言的,Groovy 大家應該很熟悉吧,是基於 Java Virtual Machine 的敏捷開發語言,它結合了 Python、 Ruby 和 Smalltalk 的許多強大的特性,如果你是一個 Ant 的完全支持者,也沒有問題,因為 Gradle 可以很平滑的來調用 Ant 文件的,我這樣說你可能不接受 Gradle,下面我們就會通過一個個具體實例來 講解 Ant,Maven,Gradle 構建項目的過程,通過例子我們能很容易明白它們的差異。Let ’ s go。
用 Ant 來構建簡單系統
新建一個 Java project, 命名為 ant_project
圖 1. 新建 ant_project 項目
然後新建一個 HelloWorld 類,我們下面就是將這個項目通過 Ant 來編譯,打包,類的代碼列表如清 單 1 所示:
清單 1. HelloWorld 類
package org.ant.test;
public class HelloWorld {
public String sayHello(String name){
return "Hello "+name;
}
}
然後再新建一個 build 文件,命名為 build.xml, 內容如清單 3 所示:
清單 2. build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="project" default="default">
<target name="default" depends="depends" description="description">
<javac srcdir="src" destdir="bin" includes="org/**"></javac>
<jar basedir="bin" destfile="dist/ant_project.jar"></jar>
<war destfile="dist/ant_project.war" webxml="WEB-INF/web.xml">
<classes dir="bin"></classes>
</war>
</target>
<!-- - - - - - - - - - - - - - - - - -
target: depends
- - - - - - - - - - - - - - - - - -->
<target name="depends">
</target>
</project>
熟悉 ant 的同學們對於上面的腳本應該很容易看明白,這裡就不詳細解釋了,主要功能就是把這個工 程編譯然後打成 jar 和 war 包。到目前為止 ant_project 的目錄結構如圖 2 所示:
圖 2. ant_project 工程目錄結構
運行 ant 腳本。
E:\gdcc\tools\apache-ant-1.6.5\bin\ant -f E:\ws_IBM\ant_project\build.xml
注:ant 放在了 E:\gdcc\tools\apache-ant-1.6.5 目錄下。
執行結果如下:
Buildfile: E:\ws_IBM\ant_project\build.xml
depends:
default:
[javac] Compiling 1 source file to E:\ws_IBM\ant_project\bin
[jar] Building jar: E:\ws_IBM\ant_project\dist\ant_project.jar
[war] Building war: E:\ws_IBM\ant_project\dist\ant_project.war
BUILD SUCCESSFUL
Total time: 859 milliseconds
這是個非常簡單的工程,我們將他打成了 jar,war 包,所需要的 build 文件大約在 10 行左右,下 面我們再看看用 Gradle 的情況。
用 Gradle 來構建簡單系統
准備環境:
下載 gradle-0.9-preview-1 從 http://dist.codehaus.org/gradle/?ref=darwinports.com網站上選 擇一個版本,然後解壓到指定目錄,將 Gradle 的 bin 目錄添加到 Path 變量中。
使用 cmd 命令,然後敲入 gradle – version,如出現以下信息,表示環境配置成功。
C:\Documents and Settings\suchu>gradle -version
Gradle 0.9-preview-1
Gradle buildtime: Monday, March 29, 2010 4:51:14 PM CEST
Groovy: 1.7.1
Ant: Apache Ant version 1.8.0 compiled on February 1 2010
Ivy: 2.1.0
Java: 1.6.0_12
JVM: 11.2-b01
JVM Vendor: Sun Microsystems Inc.
注:以上信息根據不同版本的 Gradle 或者不同的環境也許不同,但都是正確的。
Gradle 常用的使用方法介紹
新建一個 Java project, 命名為 gradle_project
圖 3. 新建 gradle_project 項目
然後新建一個 java bean 名為 HelloWorld 內容和上面的一樣,可以參考 ant_project。為了實現編 譯,打包功能,我們需要新建一個名為 build.gradle 的文件。文件內容見清單 3 所示:
清單 3. build.gradle 內容
apply plugin: 'java'
是不是很驚訝,的確,真的就只要這麼短短的一行,而它的功能卻是相當的強大的,能編譯,打成 jar 包,運行測試腳本等。到目前為止,項目的結構如圖 4 所示:
圖 4. gradle_project 項目結構圖
這裡需要注意一點的是,項目包的結構最好是按照 Gradle 期望的來建立,當然也可以通過配置來改 變。下面我們來運行下 build.gradle 文件。運行 cmd 命令,進入 gradle_project 項目路徑下,然後 運行 gradle build 命令,命令顯示信息如清單 5 所示。
清單 5. build.gradle 運行顯示信息
E:\ws_IBM\gradle_project>gradle build
:compileJava
:processResources
:classes
:jar
:assemble
:compileTestJava
:processTestResources
:testClasses
:test
:check
:build
BUILD SUCCESSFUL
Total time: 5.125 secs
我們再看下生成物,這個命令首先在 gradle_project 下新建了 build 目錄,build 目錄包含 classes, dependency-cache, libs,tmp 四個目錄,libs 下包含 jar 包,jar 包包含 main 下的所有 java 文件和和資源文件。一個簡單的例子到這裡就演示完了,怎麼樣是不是腳本很簡潔,用起來很簡單 ,產生想繼續學習的興趣了吧,別急,下面我們會繼續來探究 Gradle 的神奇之處。
下面我們來介紹幾個常用的命令,clean,這個命令是將剛才產生的 build 目錄刪除掉; Assemble, 這個命令是編譯 java 文件但是不運行檢查代碼質量等的命令,運行時顯示的信息如清單 6 所示:
清單 6. assemble 命令顯示的信息
E:\ws_IBM\gradle_project>gradle assemble
:compileJava
:processResources UP-TO-DATE
:classes
:jar
:assemble
BUILD SUCCESSFUL
和清單 5 比較下,他們的區別應該很容易看出來,那麼我們怎麼樣來運行檢查代碼質量的命令而不需 要打成 jar 包之類的額外工作呢,check 命令正好滿足你的要求,此命令就是編譯 java 文件並運行那 些類似 Checkstyle,PMD 等外部插件命令來檢查我們自己的源代碼。Check 命令運行顯示的信息如清單 7 所示:
清單 7. check 命令運行時信息
E:\ws_IBM\gradle_project>gradle check
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
BUILD SUCCESSFUL
這裡需要說明一點的是 Gradle 是增量式編譯的,只編譯那些有變動的 java 類或資源文件的,如 UP-TO-DATE 表示是有更新的。現在 javadoc 越來越受到人們的重視,尤其對於那些復雜的需要接口調用 的的項目,javadoc 的地位就更加突出了,如果我們使用 Ant 需要在 build 文件中增加清單 8 的片段 。
清單 8. 利用 Ant 生成 javadoc
<target name="javadoc">
<!-- destdir 是 javadoc 生成的目錄位置 -->
<javadoc destdir="${distDir}" encoding="UTF-8" docencoding="UTF-8">
<!-- dir 是你的源代碼位置,記住是 java 文件的位置而不是 class 文件的位置,第一次用 這個命令容易忽略這點 切記 -->
<packageset dir="${srcDir}">
<!-- exclude 是去掉那些不想生成 javadoc 的類文件 -->
<exclude name="${excludeClasses}" />
</packageset>
</javadoc>
</target>
然後我們用 ant javadoc 命令來運行,即可生成 javadoc。那麼我們利用 Gradle 是怎樣來生成 javadoc 的呢,都需要做那些額外的工作呢? build.gradle 文件是否需要修改呢?我們的回答是,不用 ,什麼都不用修改,什麼都不用做,只需利用 gradle javadoc 命令,即可生成我們期望的 javadoc。通 常我們新建一個項目,.classpath 文件的內容如清單 9 所示:
清單 9. .classpath 文件內容
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER
/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk1.6.0_12"/>
<classpathentry kind="output" path="bin"/>
</classpath>
通過上面的知識我們知道,Gradle 期望的目錄結構和自動生成的是有些差別的,比如源碼路徑,編譯 後的文件放置目錄等,那麼我們能不能通過 Gradle 命令來統一一下呢,使原項目結構與 Gradle 期望的 一致,以免開發者將代碼放置到了錯誤的目錄結構下,那樣 Gradle 是不管理它們的。下面我們就通過一 個簡單的方法來實現上面的需求,首先我們來簡單修改下 build.gradle 文件,添加 apply plugin: 'eclipse'這麼一行,然後我們使用命令 gradle eclipse 即可。.classpath 文件的變化如清單 9 所示 。
清單 9. 修改後的 .classpath 文件內容
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="output" path="build/classes/main"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
</classpath>
War 包是我們經常要用到的,上面我們利用 Ant 腳本生成過 war 包,那麼 Gradle 又是怎樣來生成 war 包的呢?經過上面的學習或許你已經猜出來了,需要增加一個 plugin,完全正確,只需要將 apply plugin: 'war' 這一行加入到 build.gradle 文件中,然後運行 gradle War 命令即可,簡單的簡直要命 ,是不是,呵呵!
如何在老項目上使用 Gradle
我們上面講過,Gradle 對其所能控制的目錄結構是有一定的要求的,那麼如果我們的項目已經開始很 長時間了,現在的項目結構不滿足 Gradle 的要求,那麼我們還能不能利用 Gradle 呢?答案當然是肯定 的,下面我們就介紹怎樣在老項目上使用 Gradle,方法很簡單,當然如果過於復雜我們也沒必要再這裡 介紹它了,直接使用 Ant 就好了。首先我們需要在 build.gradle 文件中增加如清單 10 所示的內容。
清單 10. 匹配老項目的結構
sourceSets {
main {
java.srcDir "$projectDir/src"
}
}
然後我們就可以使用 Gradle 提供的所有命令和方法了。
如何加入項目所依賴的 jar 包
大家都知道,一個項目在編譯過程中要依賴很多 jar 包的,在 Ant 中我們通過添加 classpath 來實 現的,如清單 11 所示。
清單 11. ant 中添加依賴的 jar 包
<path id="j2ee">
<pathelement location="${servlet.jar}" />
<pathelement location="${jsp-api.jar}" />
<pathelement location="${ejb.jar}" />
<pathelement location="${jms.jar}" />
</path>
<javac destdir="${build.classes}" srcdir="${src.dir}" debug="${javac.debug}"
deprecation="${javac.deprecation}">
<include name=" "/>
<classpath refid="j2ee"/>
</javac>
那麼 Gradle 又是怎樣來做的呢?通過上面的知識的學習,你是否有一個大概的思路呢?假如我們現 在有一個 java 類叫 HelloWorldTest,這個類中引用了 junit 這個 jar 包中的類,這時候我們用 Gradle 要怎樣來編譯這個類呢?首先我們新建一個目錄叫 libs,這個目錄就是放置項目所依賴的所有 jar 包,當然包括 HelloWorldTest 類所依賴的 junit-4.4.jar 包,然後我們要修改下 build.gradle 文件,增加內容見清單 12。
清單 12. 工程所依賴 jar 包添加方法
repositories {
flatDir(dirs: "$projectDir/libs")
}
dependencies {
compile ':junit:4.4'
}
注:repositories 相當一個存儲 jar 包的倉庫,我們可以指定本地的依賴 jar 包,也可以利用 Maven 所指定的倉庫,如 mavenCentral(); 通過 dependencies 來包含所有真正要依賴的 jar 包,格 式為 goup:name:version,':junit:4.4:' 就是表示 dirs 路徑下的 junit-4.4.jar 這個包。
如何實現 copy 工作
Copy 是我們經常要用到的一個命令,java 類的 copy,資源文件的 copy 等等。如果是 Ant 我們會 在 build.xml 文件中加入清單 13 中的內容。
清單 13. Ant 中的 copy 任務
復制單個文件到另一個文件
<copy file="myfile.txt" tofile="mycopy.txt"/>
復制單個文件到一個目錄
<copy file="myfile.txt" todir="../some/other/dir"/>
復制一個目錄到另一個目錄
<copy todir="../new/dir">
<fileset dir="src_dir"/>
</copy>
復制一部分文件到一個目錄下
<copy todir="../dest/dir">
<fileset dir="src_dir">
<exclude name="**/*.java"/>
</fileset>
</copy>
<copy todir="../dest/dir">
<fileset dir="src_dir" excludes="**/*.java"/>
</copy>
我們知道 copy 任務中有很多屬性,這裡我們就不一一列出了,我們還是主要看下 Gradle 是如何來 實現這些功能的。
使用 Gradle 實現目錄之間 copy 文件任務
我們只需要在 build.gradle 文件中加入清單 14 中的內容。
清單 14. gradle 中實現目錄間復制文件
task copyOne(type: Copy) {
from 'src/main/test'
into 'build/anotherDirectory'
}
注:把 test 目錄下的所有文件復制到 anotherDirectory 目錄下。然後我們利用命令 E:\ws_IBM\gradle_project>gradle copyOne 來執行即可。
對 copy 文件的過濾
有時候一個目錄下的文件數目很多,而我們只想復制某一部分文件,比如只復制 java 文件或資源文 件等,這時候我們就要用到 copy 任務的 include 屬性,這一點和 Ant 是一樣的。比如只復制 java 文 件到某一指定目錄,實現這個需求我們要在 build.gradle 文件中增加清單 15 的內容。
清單 15. copy java 文件到指定目錄
task copyTwo(type: Copy) {
from 'src/main/test'
into 'build/anotherDirectory'
include '**/*.java'
}
如果我們只想排除一些文件,不想把這一類文件 copy 過去,這時候我們要用到 exclude 屬性,比如 我們不想把 java 文件復制到指定目錄中,那麼我們只需要將上面清單 15 中的 include 替換成 exclude 即可。
發布 jar 文件
做項目時經常會遇到一個 project 中的類依賴另一個 project 中類的情況,如果用 Ant,我們會這 樣做,首先將被依賴的類文件打成 jar 包,然後利用 copy 命令將這個 jar 包復制到指定目錄下,我們 可以想象到要向 build.xml 添加好多行代碼,這裡我們就不一一列出了,不會的同學們可以參考上面的 知識。下面我們看下 Gradle 是怎樣來完成這一需求的,Gradle 不但可以講 jar 包發布到本地的指定目 錄中,而且還可以發布到遠程目錄中,我們看下清單 16 的內容。
清單 16. 發布 jar 包到本地目錄
publishJarFile {
repositories {
flatDir(dirs: file('jarsDerectory'))
}
}
然後我們利用 gradle publishJarFile 命令即可。注:清單 16 是將工程下的 java 類文件全部打成 jar 包,然後放到工程目錄下的 jarsDerectory 子目錄中。
Maven 對於 jar 包的倉庫管理方法給我們提供了很多方便,Gradle 完全可以利用 Maven 的這一優點 的,我們在上面已經講過了如何來使用,那麼我們又是怎麼來做到將項目所需要的 jar 包更新到倉庫中 呢?具體解決方法見清單 17。
清單 17. 發布 jar 文件到 Maven 的倉庫中
apply plugin: 'maven'
publishToMaven {
repositories.mavenDeployer {
repository(url: "file://localhost/tmp/myRepo/")
}
}
Gradle 在多個工程中的應用
做項目時候,經常會碰到多個工程的情況,最通常的情況我們也分為服務器端和客戶端兩部分,這種 情況我們過去用 Ant 時候會在每個工程下面都建立個 build.xml 文件或者建立一個 build.xml 文件, 然後在這個 build.xml 文件中建立不同工程的 target,將將被引用的工程打成 jar 包來供其他工程引 用,那麼 Gradle 是怎樣來完成這樣的需求的呢?下面我們舉個具體的例子來詳細演示下。首先我們新建 一個主工程命名為 gradle_multiProject, 然後在主工程下在新建一個子工程命名為 sub_projectOne, 在兩個工程下面都有一個各自獨立的 src 並且符合 Gradle 要求的目錄結構,在每個工程下面都建個類 命名為 HelloWorld,類內容同清單 1. 然後我們新建個 settings.gradle 文件,內容見清單 18。
清單 18. settings.gradle 文件內容
include "sub_projectone"
然後在新建一個我們熟悉的 build.gradle 文件,文件內容見清單 19。
清單 19. 主工程目錄下 build.gradle 文件內容
Closure printProjectName = { task -> println "I'm $task.project.name" }
task hello << printProjectName
project(':sub_projectone') {
task hello << printProjectName
}
然後我們使用命令 gradle – q hello 運行一下,運行結果如清單 20 所示。
清單 20. 命令運行結果
E:\ws_IBM\gradle_multiProject>gradle -q hello
I'm gradle_multiProject
I'm sub_projectone
我們會發現,這個命令將主工程和子工程的名字都打印出來了,為什麼會這樣呢?我想你一定猜對了 ,因為我們在 build.gradle 文件中使用了 project() 方法,方法內傳入的是子工程的名稱,如果我們 子工程不止一個,那麼我們又該怎樣來調用呢?這時候我們只需要調用另一個方法 allprojects 即可, 注意 allprojects 方法是不需要傳入參數的,它返回的是當前工程和當前工程下面的所有子工程的列表 。上面演示的內容其實我們不經常用到的,這裡簡單的介紹下就是為了說明 gradle 給我們提供了好多方 法來供我們調用,在多工程的環境下我們可以靈活的使用它們來達到我們的要求,下面我們就步入正題來 看看在多工程情況下,gradle 是如何來編譯,打包各自工程的。這裡我們添加些內容到 build.gradle 文件,內容見清單 21。
清單 21. 添加到 build.gradle 文件中的內容
subprojects{
apply plugin: 'java'
}
然後我們用命令 gradle build,發現主工程下面的所有子工程都新增了一個 build 文件夾,這個文 件夾下包含編譯生成的 class 文件和 jar 文件,而主工程的 src 下的代碼卻沒有被編譯,打包。那麼 我們怎樣做能讓主工程和子工程同時被編譯,打包呢?方法很簡單,我們只需要在 build.gradle 文件中 增加 apply plugin: 'java' 這麼一行代碼,現在完整的 build.gradle 內容見清單 22。
清單 22. 完整的 build.gradle 文件內容
apply plugin: 'java'
subprojects{
apply plugin: 'java'
}
是不是很難想象,就這麼幾行代碼就完成了將所有工程中的代碼都編譯了並且都打成了 jar 文件。有 的朋友會問了,如果子工程與主工程他們打成的包不一樣,有的是需要 jar 包,有的需要打成 war 包等 等,這樣的需求我們該怎樣做呢,很簡單我們只需要在需要打成 war 包的工程下面新建立個 build.gradle 文件,該文件內容為 apply plugin: 'war',然後我們我們在主工程目錄下使用 gradle build 命令即可生成我們需要的 war 包了,Gradle 就是使用這種方法來滿足那種差異性的需求的。
使用 Ant 的朋友們一定會深有感觸的吧!也許有些朋友會有反面的一些聲音,尤其對那些 Ant 的熱 愛者們,一定會說,Ant 如果你使用的好,封裝的好一樣可以很簡潔並且也能達到這個效果的,的確是這 樣的,Gradle 只不過是把我們經常要使用的一些功能項給封裝成了方法,然後我們調用這些方法即可了 ,再說了,Gradle 調用 Ant 腳本也是可以的,如果你一定要用 Ant, 那麼你用 Gradle 來組織一下邏輯 也是不錯的選擇。下面我們簡單看下在 Gradle 中式怎樣來調用 Ant 腳本的。
Gradle 中調用 Ant 腳本
首先我們建立 Ant 文件 build.xml, 文件詳細內容見清單 23.
清單 23. build.xml 文件內容
<project>
<target name="hello">
<echo>Hello, from Ant</echo>
</target>
</project>
然後我們在建立個 build.gradle 文件,文件詳細內容見清單 24。
清單 24. build.gradle 文件內容
ant.importBuild 'build.xml'
簡單吧,一句話的事情而已,呵呵。然後我們使用 gradle hello 命令來看下結果,結果見清單 25。
清單 25. Gradle 調用 Ant 文件的運行結果
E:\gdcc\me\gradle-0.9-preview-1\samples\userguide\ant\hello>gradle hello
:hello
[ant:echo] Hello, from Ant
BUILD SUCCESSFUL
Total time: 9.734 secs
可以看出,的確調用的是 Ant 的 build.xml 文件吧。
總結
本教程通具體實例來講解如何使用 Gradle 來構建工程的,並在具體實例中引入我們熟悉的 Ant 來對 比完成,這樣能使 Ant 的愛好者們能更快的上手,並能一目了然的看到兩者的優缺點,最後並講解了怎 樣和 Ant 來集成,每一個實例都是通過從新建工程開始一步一步的帶領大家來繼續的,我們知道僅僅通 過一片文章來很詳細的將 Gradle 的方方面面都闡述的很清楚,那是不可能的,本教程提供了最基本,最 基礎的開發過程,任何復雜的事務歸根結底還是源於基礎,我一向倡導,“授之以魚,不如授之以漁”, 我想只要方向對了,知道如何下手了,就不會有大的失誤。最後祝大家工作順利。