級別: 中級
金 發(fā)華, 軟件工程師, IBM CSDL
陳 樟洪, 軟件工程師, IBM CSDL
2006 年 5 月 29 日
本文主要介紹 Ant 在多用戶(hù)開(kāi)發(fā)的情況下,如何用 Eclipse,并且根據不同的目標環(huán)境編譯不同的部署包。文中首先介紹一個(gè)場(chǎng)景,給出在開(kāi)發(fā)、編譯、部署過(guò)程中遇到的問(wèn)題;然后介紹如何用 Eclipse 來(lái)簡(jiǎn)化你的 Ant 開(kāi)發(fā)過(guò)程;文章的最后解釋如何通過(guò)編寫(xiě)有效的 Ant 腳本來(lái)提高你的工作效率。
讀者定位為具有 Java 和 Ant 使用經(jīng)驗的開(kāi)發(fā)人員。
讀者可以學(xué)習到如何使用 Ant 解決一些多用戶(hù)開(kāi)發(fā)環(huán)境中,根據不同的目標環(huán)境編譯成不同部署包的問(wèn)題。
現在有一個(gè) web 項目,是多人進(jìn)行開(kāi)發(fā)的,通過(guò) CVS 來(lái)管理。另外該項目還有一些測試人員,他們測試部署在測試服務(wù)器上的應用程序,發(fā)現 bug 后通過(guò) bug 管理系統通知開(kāi)發(fā)人員,在開(kāi)發(fā)人員修復 bug 并經(jīng)過(guò)本地測試后,由專(zhuān)門(mén)的人負責檢出(check out)代碼,編譯打包后部署到測試服務(wù)器上。
該項目的成員小A就是負責檢出代碼、編譯打包,并部署到服務(wù)器上的人。除了這個(gè)任務(wù)之外,他還是該項目的編程人員。在項目進(jìn)入測試階段后,小A在得到組中別的成員修復了 bug 并且檢入(check in)了代碼的消息后(也有可能是小A自己檢入了代碼),小A首先更新本地的代碼,先在本地做測試,確認修復了 bug 后打成 WAR 包部署到測試服務(wù)器上,并通知測試人員已經(jīng)修復了 bug,讓測試人員繼續進(jìn)行測試。
在該項目中,有一些為測試方便開(kāi)發(fā)而寫(xiě)的代碼和頁(yè)面,比如跳過(guò)用戶(hù)認證,但是在部署到測試機環(huán)境的時(shí)候,需要刪除這些代碼和頁(yè)面;另外作為一個(gè)具有靈活性和擴展性的應用程序,又有一些配置文件,配置文件中的值會(huì )根據環(huán)境的改變而變動(dòng)。例如,在項目中使用了 Log4j 記錄日志,需要給 Log4j 指定日志文件的保存路徑,本地程序員開(kāi)發(fā)的時(shí)候用的是 Windows 系統,給 Log4j 指定的也是 Windows 的文件系統,在測試階段的時(shí)候,需要部署到 Linux 系統中,那么日志的保存路徑也需要做相應的改動(dòng)。部署到測試服務(wù)器上的時(shí)候,除了 Log4j 需要改之外,還有很多別的配置項目也需要變動(dòng),并且分散在各個(gè) package 中。小A的煩惱也隨之而來(lái),每次他在做完本地測之后,就根據測試機的需要逐個(gè)找配置文件,更改相應的值,并刪除那些為測試方便寫(xiě)的代碼和頁(yè)面,每天可能根據需要做好幾次這樣的事情,最煩的是他在快做完對測試機環(huán)境更改的時(shí)候,某開(kāi)發(fā)人員突然通知小A說(shuō):“我又改了一點(diǎn)代碼,剛檢入,你再重打一個(gè)包吧。”,小A又不得不從頭開(kāi)始做新一輪的檢出代碼、本地測試、更改配置文件、刪除不需要的文件、打包部署的工作。另外小A在測試階段的后期被通知要求除了每次生成一個(gè)測試環(huán)境的 WAR 包外還必須生成一個(gè)在產(chǎn)品環(huán)境下的 WAR 包,他做的事情就更多了。
從上面的場(chǎng)景可以看出,小A的工作效率低而且容易出錯,甚至有可能導致整個(gè)項目的工作效率低下。其實(shí)可以通過(guò) Ant 來(lái)幫助小A快速而且有效地完成這個(gè)工作。在 Ant 中,根據目標環(huán)境的需要,可以把所有要更改的配置文件的項目集中寫(xiě)到某個(gè)配置文件中。這樣根據不同的目標環(huán)境得到不同的配置文件,Ant 在編譯包時(shí)根據不同的目標環(huán)境切換不同的配置文件即可。比如小A現在碰到的有 3 中環(huán)境:開(kāi)發(fā)環(huán)境、測試環(huán)境以及產(chǎn)品環(huán)境,根據這三種環(huán)境可以生成三個(gè)不同的配置文件:develop_deploy.property、test_deploy. property和product_deploy. property,當小A想生成不同的包時(shí)只需在這三個(gè)配置文件之間切換就可以了。
在正式開(kāi)始編寫(xiě)腳本之前,我們需要下載安裝相應的軟件。
![]() ![]() |
![]()
|
用 Eclipse3.1 來(lái)創(chuàng )建 Ant 腳本
如果你使用 Eclipse 來(lái)編寫(xiě) Ant,建議使用 Eclipse 3.1 以后的版本。除了以前 Ant 編輯器提供的語(yǔ)法高亮,提示語(yǔ)法錯誤等功能外,Eclipse3.1 版本增加了許多新的功能。比如:腳本代碼的折疊;快速定位某屬性或者目標(target)段的定義;在同一 builder 文件中重構屬性名和目標名(快捷方式Alt + Shift +R);調試 Ant 腳本等。
下面我們就來(lái)看看 Eclipse 3.1 中對 Ant 的支持
打開(kāi)“File”-“New”-“Project”-“Simple”-“Project”,點(diǎn)擊“Next”,輸入工程名“Ant”,然后點(diǎn)擊直到“Finish”
在新建的 Ant 工程中,新建 Test.xml,并且拷貝下面的腳本。該段腳本的內容就不做介紹了,我們主要看 Eclipse 提供了哪些功能。注意這時(shí)候打開(kāi)的并不是 Ant 編輯器,將內容拷貝進(jìn)去之后,關(guān)掉打開(kāi)的“Test.xml”,然后再重新打開(kāi)它,這樣 Eclipse 就會(huì )用 Ant 編輯器打開(kāi)它,并且也語(yǔ)法高亮了。
|
自動(dòng)提示和代碼折疊功能。如果是 Ant 內置的命令或者前面已經(jīng)定義的變量,編輯器會(huì )自動(dòng)提示;編輯器右邊的加/減號可以代碼折疊。如下所示:

快速定位目標(target)或者定義變量處。在上圖中,將鼠標移至 default=”init” 中的 init 上之后,按下 ctrl 鍵,鼠標變成手狀,單擊就可以定位到定義該目標的地方
快速重構目標名或者屬性名。選中目標/屬性名,按下 Alt + Shift + R,然后鍵入你要修改后的值,所有引用到的地方都會(huì )隨之改動(dòng)。如下圖所示,選中 init 后,按下快捷鍵,改成 initial:

調試 Ant 腳本。在標簽“<target name=..”的左邊設置一斷點(diǎn),然后在編輯器中右擊,出現的菜單中選“Debug As”-“Ant Build”,出現后的窗口與調試 Java 程序的界面差不多。
這是調試窗口,這里可以選擇單步跟進(jìn)、跳出等:

下面是運行時(shí)變量窗口??梢钥吹?test 變量的值是“test”:

運行結果窗口:

由此可見(jiàn),如果使用好 Eclipse Ant 編輯器所提供強大的功能的話(huà)能大大提高寫(xiě) Ant 腳本的效率。
![]() ![]() |
![]()
|
剛開(kāi)始寫(xiě) Ant 的初學(xué)者可能會(huì )把所有的信息都放在 build.xml 中,下面就是這樣的一個(gè)例子。
|
在上面的例子中,所有的路徑信息都是寫(xiě)在 build.xml 中。但是 Ant 腳本可能在不同的機器或者不同的系統上運行,也有可能一些值需要根據環(huán)境的不同而變化,在 Ant 中可以把所有這些可能變化的地方都放到一個(gè)配置文件中,然后在 Ant 腳本中引用這個(gè)配置文件就可以了,針對上面的例子,如下所示:
|
如果想在 Ant 腳本中引用值的話(huà),只需用$符號開(kāi)頭,在一對"{}"中寫(xiě)入要引用的鍵值。如上例中,需要引用編譯的目標路徑用"${dest.dir}"。
![]() ![]() |
![]()
|
使用 Ant 任務(wù)從 CVS 中檢出(check out)源代碼,并編譯打包
Ant 中提供了 cvs 任務(wù)(Task)可以從 CVS 服務(wù)器中檢出資源(注意:在使用 Ant 的 cvs 任務(wù)之前,請先將 cvs.exe 下載到你的機器,并且將它添加到你本地的 PATH 環(huán)境變量中,然后重新啟動(dòng) Eclipse。否則在執行下面腳本的時(shí)候就會(huì )得到 error=2 的錯誤)。cvs 的可選用屬性很多,在這里介紹經(jīng)常使用到的幾個(gè)屬性。從 CVS 中檢出資源一般需要指定:
在介紹使用 Ant 的 cvs 之前,先說(shuō)一下本地的目錄結構。在 C 盤(pán)的 temp 目錄下,分別有四個(gè)目錄,如下所示:

在 Ant 中這樣寫(xiě)就可以從中檢出資源:
|
這段腳本片斷的意思就是從叫"cvs.server"的服務(wù)器中,用用戶(hù)名是 username、密碼為 pwd 的用戶(hù)檢出在庫路徑是 /home/testPath 下的 TestProj 模塊(項目),檢出后的資源放入本地目錄 c:/temp/src/testProj 中。在上面這段腳本中,可以看到有很多值可能會(huì )根據不同的環(huán)境或者用戶(hù)隨之改變的,比如用戶(hù)名和密碼等;而且從腳本的重復可利用性來(lái)說(shuō),需要把有些值抽出來(lái)放到配置文件中,如服務(wù)器的地址和庫路徑等。因此把這些可能需要更改的地方放到 property 文件中,效果會(huì )更好。改完后的完整 Ant 腳本如下所示:
|
對應的 TestWeb.properties 文件內容如下所示:
|
在檢出了資源后,需要對其進(jìn)行編譯打包。為了使 Ant 腳本更加具有可讀性和靈活性,我們需要對上面的 Ant 腳本進(jìn)行一些改動(dòng)。首先將 Ant 腳本中進(jìn)行分段,如下所示:
|
上面的腳本中,總共分成了5個(gè)目標(target),腳本的入口點(diǎn)是"all",all 按順序調用 init,clean,checkout,build。其中:
詳細的 Ant 腳本可以參見(jiàn)隨本文所附的 TestWeb.xml 和 TestWeb.properties。
![]() ![]() |
![]()
|
編譯過(guò)程與產(chǎn)生不同目標環(huán)境的腳本分開(kāi)執行
在前面介紹的 Ant 腳本中,根據從 CVS 服務(wù)器中檢出的資源打成了一個(gè)默認的 war 包,并沒(méi)有考慮根據不同的目標環(huán)境來(lái)生成不同的包,從下一節開(kāi)始介紹如何根據不同的環(huán)境來(lái)生成不同的部署包。
還有一個(gè)問(wèn)題是:為什么需要把從 CVS 中檢出資源、編譯的過(guò)程跟根據目標環(huán)境打包的過(guò)程分開(kāi)?
這是因為本身 CVS 檢出資源是需要花一定的時(shí)間,如果資源比較多這個(gè)過(guò)程就會(huì )花費挺長(cháng)時(shí)間;另外,在多人開(kāi)發(fā)的情況下必須保證在生成不同的部署包的時(shí)候是用的是同一套代碼生成的,否則會(huì )出現各個(gè)服務(wù)器上運行的版本不一致,如果檢出資源、編譯的過(guò)程跟生成包的腳本一起執行的話(huà)就會(huì )出現這個(gè)問(wèn)題(比如小A在測試服務(wù)器測試通過(guò)的時(shí)候之后,再生成一個(gè)在產(chǎn)品環(huán)境下的部署包,如果分兩次從 CVS 服務(wù)器中檢出資源的話(huà),在此期間可能會(huì )有開(kāi)發(fā)人員往 CVS 服務(wù)器中檢入代碼,導致生成的版本不一致),因此,必須將這兩個(gè)過(guò)程分開(kāi)執行?,F在我們開(kāi)始建立另外一個(gè) Ant 腳本文件,叫 deploy.xml,專(zhuān)門(mén)用來(lái)生成包;另外與 deploy.xml 相對應的還有一個(gè) deploy.properties 文件。在 deploy.xml 中會(huì )引用 deploy.properties 文件。另外根據在前面的場(chǎng)景中碰到的環(huán)境,創(chuàng )建三個(gè)不同的屬性文件, develop_deploy.property、test_deploy. property 和 product_deploy. Property,在打包的時(shí)候,根據不同的目標環(huán)境,將相應屬性文件中的內容拷貝至 deploy.properties 文件中(或者也可以直接在 deploy.xml 中直接切換不同的屬性文件),然后在 Eclipse 中直接執行 deploy.xml;如果在命令行中,可以用下面的命令來(lái)執行:
|
![]() ![]() |
![]()
|
我們首先得建立一個(gè)目錄(這里是 unpack)用來(lái)存放解壓后的文件。Ant 中提供了 unzip 命令用來(lái)解壓 ear/war/jar 包。除了這個(gè)目錄外,根據不同的目標環(huán)境,在運行目錄下建立一個(gè)與目標環(huán)境相對應的目錄,重新打好的 war 包就放在這個(gè)目錄下,比如針對場(chǎng)景中的情況,如果需要創(chuàng )建一個(gè)產(chǎn)品環(huán)境下的部署包,我們可以建立一個(gè) TestWebProduct 目錄,目錄名寫(xiě)在配置文件中(${pack.base.dir})。
|
在 init 段中首先刪除掉上次解壓的目錄和目標打包目錄,然后重新建立目錄;在 unpack 中,首先將編譯好的默認 war 包拷貝至 unpack 定義的目錄,解壓之后把 unpack 下的 war 包刪除。下面是這時(shí)候對應的屬性文件。
|
![]() ![]() |
![]()
|
現在根據不同環(huán)境的需要,對某些配置文件的值做一些替換。在 Ant 中,提供了 filter 任務(wù),使得替換值很方便。當然也可以使用下面介紹的正則表達式來(lái)替換屬性值。filter 主要用來(lái)在同一行內容中的替換,而正則表達式一下子可以替換多行內容。filter 的使用例子:
|
這段腳本的意思就是在 src.dir 目錄下的所有文件中,如果有預先定義好的"@log4j.logger@"占位符的話(huà),在拷貝到 dest.dir 目錄后,所有的占位符都被替換成了"INFO"。
你也可以將所有被替換的值放到某個(gè)屬性文件中,filter 任務(wù)將屬性文件中的每一個(gè)條目讀出來(lái)并且設置成一個(gè) Filter。如下所示:
|
上面的腳本表示所有在 deploy_env 中出現的條目將被作為一個(gè) filter,在拷貝到 dest.dir 目錄后,所有 src.dir 目錄中存在的占位符將被替換成 deploy_env 中的值。具體的例子可以參見(jiàn)隨本文附帶的 deploy.xml, deploy_env.properties 和 Test.properties。
其中 deploy.xml 是 ant 腳本,deploy_env.properties 中包含所有要替換的值,在 Test.properties 中是包含有占位符的資源文件。
![]() ![]() |
![]()
|
Ant 中支持多種正則表達式,在運行 Ant 的時(shí)候用哪種正則表達式可以通過(guò)設置 ant.regexp.regexpimpl 的值來(lái)切換,Ant 支持的的正則表達式有:
正則表達式的例子:
|
byline 屬性用來(lái)確認被替換的時(shí)候是一次替換一行還是多行;pattern 屬性用來(lái)指明正則表達式;substitution expression 中是替換的值,替換的值都定義在相對應的配置文件中;fileset 屬性中的 dir 用來(lái)指定被替換文件所在的目錄,includes 用來(lái)指定要替換哪個(gè)文件。需要注意的是,如果在正則表達式或者替換的值中出現"<"的話(huà),需要用轉義符"<"。
在 Eclipse3.1 中已經(jīng)內置了對正則表達式的支持;但是如果你在命令行中運行需要正則表達式支持的腳本的話(huà),則需要自己將正則表達式的包下載下來(lái)加到 classpath 中。在隨文章的 deploy.xml 中提供了一個(gè)簡(jiǎn)單的替換屬性文件的值的例子。正則表達式的例子可以在本文所帶的 deploy.xml 中找到。
![]() ![]() |
![]()
|
在生成部署包的時(shí)候,還有可能會(huì )根據目標環(huán)境的不同,刪除一些不同的文件。比如在產(chǎn)品環(huán)境中那些作為測試需要的代碼往往需要刪除,但是測試環(huán)境中并不需要。因此就需要條件表達式來(lái)做判斷。如下所示:
|
在上面的例子中,先讀出 ${deploy.isTestEnv} 的值(在配置文件 deloy.properties 中),根據讀出的值對屬性 isTestEnv 設值,如果 ${deploy.isTestEnv} 的值是 true,isTestEnv 的值也是 true;否則是 false。然后分別調用目標段 trueCondition 和 falseCondition。在這里,表達式值的判斷是用"istrue",在 Ant 中還提供了很多別的表達式,比如 not/and/or,equals 等等,具體關(guān)于條件表達式的信息可以參考:http://ant.apache.org/manual/CoreTasks/condition.html ,該頁(yè)也可以在隨下載下來(lái)的文檔中找到。
在段 trueCondition 中,判斷 isTestEnv,如果是真的話(huà)就運行,否則不運行;在段 falseCondition 中,也判斷 isTestEnv,如果是假就運行,否則不運行,在段中可以根據情況做相應的事情。條件判斷式的例子可以在本文的 deploy.xml 中找到。
![]() ![]() |
![]()
|
在上面的替換過(guò)程完成后,調用 war 將 unpack 目錄下的內容重新打包。
|
詳細的例子可以參見(jiàn)隨本文的附件 deploy.xml 和 deploy.properties。
![]() ![]() |
![]()
|
通過(guò)本文可以看出編寫(xiě)好有效的 Ant 腳本能很好的解決在編譯部署包的時(shí)候出現的問(wèn)題,將那些變化的內容放到配置文件中,在部署的時(shí)候切換不同的配置文件就可以實(shí)現生成不同的部署包。文中也介紹了如何使用 Eclipse 來(lái)提高你編寫(xiě)/調試 Ant 腳本的效率。
![]() ![]() |
![]()
|
| 描述 | 名字 | 大小 | 下載方法 |
|---|---|---|---|
| Source code | Ant.zip | 4KB | HTTP |
![]() | ||||
![]() | 關(guān)于下載方法的信息 | ![]() | ![]() | Get Adobe® Reader® |
![]() ![]() |
![]()
|
![]() ![]() |
![]()
|
![]() | ||
![]() | 金發(fā)華是一名工作在 IBM CSDL 的軟件工程師。他喜歡鉆研各種新的技術(shù),在 Java 網(wǎng)絡(luò )開(kāi)發(fā)和 Web 開(kāi)發(fā)方面頗有經(jīng)驗。 | |
![]() | ||
|
| ![]() | 陳樟洪是一位 IBM CSDL 的軟件工程師,目前從事企業(yè)電子商務(wù)應用的開(kāi)發(fā)。 |
聯(lián)系客服