Ant 下载、安装、使用、教程全面了解「建议收藏」
Eclipse 內(nèi)置了 Ant 。 Ant 是一種類似于批處理程序的軟件包,它主要繁瑣的工作是編寫和調(diào)試自動處理腳本(一個 XML 文件),但只要有了這個腳本,我們就可以一鍵完成所有的設(shè)定工作。
本節(jié)還是以 myswt 這個應(yīng)用程序項(xiàng)目的打包為例,用 Ant 來完成“編譯->打成 JAR 包->復(fù)制項(xiàng)目引用庫->復(fù)制本地化文件 swt-win32-3063.dll ->輸出 API 文檔”這五步。
1 、在 myswt 項(xiàng)目根目錄下,創(chuàng)建最主要的 build.xml 文件
<?xml version=1.0?>
<project name=myswt project default=api_doc>
<!– 定義目錄變量 –>
<property name=src.dir value=src />
<property name=bin.dir value=bin />
<property name=eclipse_plugins.dir value=c:/eclipse/plugins />
<property name=dist.dir value=d:/dist />
<property name=doc.dir value=${dist.dir}/api />
<property name=swt.dll value=swt-win32-3063.dll />
<!– 定義編譯文件時所引用的庫 –>
<path id=master-classpath>
<fileset dir=${eclipse_plugins.dir} id=project_lib>
<include name=org.eclipse.ui.workbench_3.0.1/workbench.jar/>
<include name=org.eclipse.swt.win32_3.0.1/ws/win32/swt.jar/>
<include name=org.eclipse.jface_3.0.0/jface.jar/>
<include name=org.eclipse.osgi_3.0.1/osgi.jar/>
<include name=org.eclipse.osgi_3.0.1/core.jar/>
<include name=org.eclipse.osgi_3.0.1/resolver.jar/>
<include name=org.eclipse.osgi_3.0.1/defaultAdaptor.jar/>
<include name=org.eclipse.osgi_3.0.1/eclipseAdaptor.jar/>
<include name=org.eclipse.osgi_3.0.1/console.jar/>
<include name=org.eclipse.core.runtime_3.0.1/runtime.jar/>
<include name=org.eclipse.jface.text_3.0.1/jfacetext.jar/>
<include name=org.eclipse.ui.workbench.compatibility_3.0.0/compatibility.jar/>
</fileset>
</path>
<!– 首任務(wù)(空) –>
<target name=init/>
<!– 編譯 –>
<target name=compile depends=init>
<delete dir=${bin.dir}/>
<mkdir dir=${bin.dir}/>
<!– 編譯源程序 –>
<javac srcdir=${src.dir} destdir=${bin.dir} target=1.4>
<classpath refid=master-classpath/>
</javac>
<!– 復(fù)制圖標(biāo)目錄 –>
<mkdir dir=${bin.dir}/icons/>
<copy todir=${bin.dir}/icons>
<fileset dir=icons/>
</copy>
</target>
<!– 打包 –>
<target name=pack depends=compile>
<!– bin 目錄壓縮成 JAR 包 –>
<delete dir=${dist.dir}/>
<mkdir dir=${dist.dir} />
<jar basedir=${bin.dir} destfile=${dist.dir}/myswt.jar manifest=ant_manifes.txt>
<exclude name=**/*Test.* />
<exclude name=**/Test*.* />
</jar>
<!– 復(fù)制用到的庫 –>
<mkdir dir=${dist.dir}/lib />
<copy todir=${dist.dir}/lib>
<fileset refid=project_lib/>
</copy>
<!– 復(fù)制本地化文件 –>
<copy todir=${dist.dir} file=${swt.dll}/>
</target>
<!– 輸出 api 文檔 –>
<target name=api_doc depends=pack>
<delete dir=${doc.dir}/>
<mkdir dir=${doc.dir} />
<javadoc destdir=${doc.dir} author=true version=true use=true windowtitle=MySWT API>
<packageset dir=${src.dir} defaultexcludes=yes/>
<doctitle><![CDATA[<h1>MySWT Project</h1>]]></doctitle>
<bottom><![CDATA[<i>Document by ChenGang 2005.</i>]]></bottom>
</javadoc>
</target>
</project>
代碼說明:
( 1 ) property 項(xiàng)是定義變量,比如 <property name=swt.dll value=swt-win32-3063.dll /> ,就是定義一個變量: swt.dll=swt-win32-3063.dll 。以后用這個變量則是這樣: ${swt.dll} 。
一般盡量將今后可能會變動的目錄、文件等定義成變量,以方便維護(hù)。不象 Java 變量有類型的區(qū)分, Ant 變量是不區(qū)別目錄、文件等的,所以為了見名知意,在取變量名時,目錄都加“ dir ”后綴,這個后綴是可以任取名的。
下面給出本例用到的變量的含義:
l src.dir - Java 源文件路徑。 value=src 的 src 是一個相對路徑,它相對的是 build.xml 的所在目錄位置(即項(xiàng)目根目錄)。
l bin.dir - Java 編譯文件的輸出路徑
l eclipse_plugins.dir - eclipse 的 plugins 目錄
l dist.dir - 打包文件的存放目錄
l doc.dir - API 文檔的存放目錄,這里用到了 dist.dir 變量,直接寫 value=d:/dist/api 也未嘗不可。
l swt.dll - SWT 本地化文件。
( 2 ) <path id=master-classpath> ,定義編譯文件時所引用的庫,相當(dāng)于 classpath 。 <fileset> 項(xiàng)表示一個文件集,再深入一層的 <include> 項(xiàng),則表示此文件集下的文件,它們的路徑定位相對于 <fileset> 的 dir 屬性。 <fileset> 還有一個 id 屬性,在后面復(fù)制引用庫時會用到。
也許有讀者會問:“你是怎么知道要引用這些文件的?”回答:看項(xiàng)目根目錄下的“ .classpath ”文件,就可以知道本項(xiàng)目要引用那些庫了。實(shí)際上筆者是把 .classpath 復(fù)制一份后,然后用 Editplus 編輯而得。
( 3 )接下來開始定義一些任務(wù)。首任務(wù)一般都讓它為空(沒有具體任務(wù)內(nèi)容): <target name=init/> 。
( 4 ) Ant 中的任務(wù)有著相互的依賴( depends )關(guān)系,這些依賴關(guān)系是通過 depends 屬性來定義的。當(dāng)要執(zhí)行一個任務(wù)時, Ant 先去執(zhí)行這個任務(wù)的 depends 任務(wù),……, Ant 就這樣一直往回找下去。比如:在本例的第二行 default=api_doc ,它定義了缺省任務(wù)是 api_doc (輸出 api 文檔)->此任務(wù)的 depends = pack (打包)-> pack 的 depends = compile (編譯)-> compile 的 depends=init (首任務(wù)), init 沒有 depends 。于是, Ant 就從 init 開始依次往回執(zhí)行任務(wù): init -> compile -> pack -> api_doc 。
如果你不想“輸出 api 文檔”,則將第二行的缺省任務(wù)定義成 default=pack 即可,這時整個任務(wù)鏈就拋開了 api_doc 。
( 5 ) <delete dir=${bin.dir}/> 刪除目錄。 <mkdir dir=${bin.dir}/> 新建目錄
( 6 )編譯源程序,如下
<javac srcdir=${src.dir} destdir=${bin.dir} target=1.4>
<classpath refid=master-classpath/>
</javac>
l srcdir - 源文件目錄,其子目錄中的源文件也會被 javac.exe 編譯。
l destdir - 編譯文件輸出目錄。
l target - 以 JDK1.4 為編譯目標(biāo)。
l classpath - 編譯的 classpath 設(shè)置, refid 是指引用前面設(shè)定的 master-classpath 。
( 7 )將 icons (即 myswt/icons )目錄的文件,復(fù)制到 myswt/bin/icons 目錄中,如下:
<copy todir=${bin.dir}/icons>
<fileset dir=icons/>
</copy>
( 8 )將文件打成 JAR 包
<jar basedir=${bin.dir} destfile=${dist.dir}/myswt.jar manifest=ant_manifes.txt>
<exclude name=**/*Test.* />
<exclude name=**/Test*.* />
</jar>
l basedir - 源目錄。
l destfile - 目標(biāo)目錄和打成 JAR 包名。
l manifest - 打包清單文件(后面給出其內(nèi)容)。
l exclude - 使用了通配符將某一些文件排除不打包(主要是一些測試文件)。
( 9 )如下,將 project_lib 的文件復(fù)制到 d:/dist/lib 目錄中。 project_lib 是前面“定義編譯文件時所引用的庫”中的文件集的 id 。結(jié)果參數(shù)下圖 21.25
<copy todir=${dist.dir}/lib>
<fileset refid=project_lib/>
</copy>
( 10 )將本地化文件復(fù)制到 d:/dist 目錄中,如下:
<copy todir=${dist.dir} file=${swt.dll}/>
( 11 )輸出 API 文檔(結(jié)果參數(shù)下圖 21.26 )
<javadoc destdir=${doc.dir} author=true version=true use=true windowtitle=MySWT API>
<packageset dir=${src.dir} defaultexcludes=yes/>
<doctitle><![CDATA[<h1>MySWT Project</h1>]]></doctitle>
<bottom><![CDATA[<i>Document by ChenGang 2005.</i>]]></bottom>
</javadoc>
l destdir - 目標(biāo)路徑 d:/dist/api
l packageset - 源文件目錄
l doctitle - 標(biāo)題
l bottom - 標(biāo)尾。
2 、創(chuàng)建打包清單
為了避免和原來的 manifes.txt 同名,在項(xiàng)目根目錄建立一個名為 ant_manifes.txt 的文件。這個文件內(nèi)容中最長的是 Class-Path 項(xiàng),沒有必要一個個字符的敲入,它可以由項(xiàng)目根目錄下的“ .classpath ”編輯而得。
ant_manifes.txt 內(nèi)容如下:
Manifest-Version: 1.0
Main-Class: jface.dialog.wizard.WizardDialog1
Class-Path: ./lib/org.eclipse.ui.workbench_3.0.1/workbench.jar ./lib/org.eclipse.swt.win32_3.0.1/ws/win32/swt.jar
./lib/org.eclipse.jface_3.0.0/jface.jar ./lib/org.eclipse.osgi_3.0.1/osgi.jar ./lib/org.eclipse.osgi_
3.0.1/core.jar ./lib/org.eclipse.osgi_3.0.1/resolver.jar ./lib/org.eclipse.osgi_3.0.1/defaultAdaptor.ja
r ./lib/org.eclipse.osgi_3.0.1/eclipseAdaptor.jar ./lib/org.eclipse.osgi_3.0.1/console.jar ./lib/org.ecl
ipse.core.runtime_3.0.1/runtime.jar ./lib/org.eclipse.jface.text_3.0.1/jfacetext.jar ./lib/org.eclipse.u
i.workbench.compatibility_3.0.0/compatibility.jar
3 、如下圖 21.23 所示,選擇“ Ant 構(gòu)建”來運(yùn)行 Ant 。
圖 21.23 運(yùn)行“ Ant 構(gòu)建”
運(yùn)行“ Ant 構(gòu)建”后的結(jié)果如下圖 21.23 - 26 所示。
圖 21.24 控制臺的輸出
圖 21.25 輸出文件的目錄結(jié)構(gòu)圖
圖 21.26 輸出的 API 文檔效果圖
4 、運(yùn)行打包結(jié)果
除了清單文件 MANIFEST.MF 之外, myswt.jar 文件和 21.1 節(jié)所得的 myswt.jar 一樣。本節(jié)沒有創(chuàng)建 run.bat 批處理文件,而是用下圖 21.27 所示的“右擊 myswt.jar ->打開方式-> javaw ”的方式來運(yùn)行 myswt.jar 。
圖 21.27 運(yùn)行 myswt.jar
ant命令總結(jié)
1Ant是什么
ApacheAnt是一個基于Java的生成工具。
生成工具在軟件開發(fā)中用來將源代碼和其他輸入文件轉(zhuǎn)換為可執(zhí)行文件的形式(也有可能轉(zhuǎn)換為可安裝的產(chǎn)品映像形式)。隨著應(yīng)用程序的生成過程變得更加復(fù)雜,確保在每次生成期間都使用精確相同的生成步驟,同時實(shí)現(xiàn)盡可能多的自動化,以便及時產(chǎn)生一致的生成版本
2下載、安裝Ant
安裝Ant
下載.zip文件,解壓縮到c:/ant1.3(后面引用為%ANT_HOME%)
2.1在你運(yùn)行Ant之前需要做一些配置工作。
?將bin目錄加入PATH環(huán)境變量。
?設(shè)定ANT_HOME環(huán)境變量,指向你安裝Ant的目錄。在一些OS上,Ant的腳本可以猜測ANT_HOME(Unix和WindosNT/2000)-但最好不要依賴這一特性。
?可選地,設(shè)定JAVA_HOME環(huán)境變量(參考下面的高級小節(jié)),該變量應(yīng)該指向你安裝JDK的目錄。
注意:不要將Ant的ant.jar文件放到JDK/JRE的lib/ext目錄下。Ant是個應(yīng)用程序,而lib/ext目錄是為JDK擴(kuò)展使用的(如JCE,JSSE擴(kuò)展)。而且通過擴(kuò)展裝入的類會有安全方面的限制。
2.2運(yùn)行Ant
運(yùn)行Ant非常簡單,當(dāng)你正確地安裝Ant后,只要輸入ant就可以了。
? 沒有指定任何參數(shù)時,Ant會在當(dāng)前目錄下查詢build.xml文件。如果找到了就用該文件作為buildfile。如果你用-find選項(xiàng)。 Ant就會在上級目錄中尋找buildfile,直至到達(dá)文件系統(tǒng)的根。要想讓Ant使用其他的buildfile,可以用參數(shù)– buildfilefile,這里file指定了你想使用的buildfile。
?可以指定執(zhí)行一個或多個target。當(dāng)省略target時,Ant使用標(biāo)簽<project>的default屬性所指定的target。
命令行選項(xiàng)總結(jié):
ant[options][target[target2[target3]…]]
Options:
-helpprintthismessage
-projecthelpprintprojecthelpinformation
-versionprinttheversioninformationandexit
-quietbeextraquiet
-verbosebeextraverbose
-debugprintdebugginginformation
-emacsproducelogginginformationwithoutadornments
-logfilefileusegivenfileforlogoutput
-loggerclassnametheclassthatistoperformlogging
-listenerclassnameaddaninstanceofclassasaprojectlistener
-buildfilefileusespecifiedbuildfile
-findfilesearchforbuildfiletowardstherootofthefilesystemandusethefirstonefound
-Dproperty=valuesetpropertytovalue
例子
ant
使用當(dāng)前目錄下的build.xml運(yùn)行Ant,執(zhí)行缺省的target。
ant-buildfiletest.xml
使用當(dāng)前目錄下的test.xml運(yùn)行Ant,執(zhí)行缺省的target。
ant-buildfiletest.xmldist
使用當(dāng)前目錄下的test.xml運(yùn)行Ant,執(zhí)行一個叫做dist的target。
ant-buildfiletest.xml-Dbuild=build/classesdist
使用當(dāng)前目錄下的test.xml運(yùn)行Ant,執(zhí)行一個叫做dist的target,并設(shè)定build屬性的值為build/classes。
3編寫build.xml
Ant的buildfile是用XML寫的。每個buildfile含有一個project。
buildfile中每個task元素可以有一個id屬性,可以用這個id值引用指定的任務(wù)。這個值必須是唯一的。(詳情請參考下面的Task小節(jié))
3.1Projects
project有下面的屬性:
AttributeDescriptionRequired
name項(xiàng)目名稱.No
default當(dāng)沒有指定target時使用的缺省targetYes
basedir用于計(jì)算所有其他路徑的基路徑。該屬性可以被basedirproperty覆蓋。當(dāng)覆蓋時,該屬性被忽略。如果屬性和basedirproperty都沒有設(shè)定,就使用buildfile文件的父目錄。No
項(xiàng)目的描述以一個頂級的<description>元素的形式出現(xiàn)(參看description小節(jié))。
一個項(xiàng)目可以定義一個或多個target。一個target是一系列你想要執(zhí)行的。執(zhí)行Ant時,你可以選擇執(zhí)行那個target。當(dāng)沒有給定target時,使用project的default屬性所確定的target。
3.2Targets
一個target可以依賴于其他的target。例如,你可能會有一個target用于編譯程序,一個target用于生成可執(zhí)行文件。你在生成可執(zhí)行文件之前必須先編譯通過,所以生成可執(zhí)行文件的target依賴于編譯target。Ant會處理這種依賴關(guān)系。
然而,應(yīng)當(dāng)注意到,Ant的depends屬性只指定了target應(yīng)該被執(zhí)行的順序-如果被依賴的target無法運(yùn)行,這種depends對于指定了依賴關(guān)系的target就沒有影響。
Ant會依照depends屬性中target出現(xiàn)的順序(從左到右)依次執(zhí)行每個target。然而,要記住的是只要某個target依賴于一個target,后者就會被先執(zhí)行。
<targetname=”A”/>
<targetname=”B”depends=”A”/>
<targetname=”C”depends=”B”/>
<targetname=”D”depends=”C,B,A”/>
假定我們要執(zhí)行targetD。從它的依賴屬性來看,你可能認(rèn)為先執(zhí)行C,然后B,最后A被執(zhí)行。錯了,C依賴于B,B依賴于A,所以先執(zhí)行A,然后B,然后C,最后D被執(zhí)行。
一個target只能被執(zhí)行一次,即時有多個target依賴于它(看上面的例子)。
如果(或如果不)某些屬性被設(shè)定,才執(zhí)行某個target。這樣,允許根據(jù)系統(tǒng)的狀態(tài)(javaversion,OS,命令行屬性定義等等)來更好地控制build的過程。要想讓一個target這樣做,你就應(yīng)該在target元素中,加入if(或unless)屬性,帶上target因該有所判斷的屬性。例如:
<targetname=”build-module-A”if=”module-A-present”/>
<targetname=”build-own-fake-module-A”unless=”module-A-present”/>
如果沒有if或unless屬性,target總會被執(zhí)行。
可選的description屬性可用來提供關(guān)于target的一行描述,這些描述可由-projecthelp命令行選項(xiàng)輸出。
將你的tstamptask在一個所謂的初始化target是很好的做法,其他的target依賴這個初始化target。要確保初始化target是出現(xiàn)在其他target依賴表中的第一個target。在本手冊中大多數(shù)的初始化target的名字是”init”。
target有下面的屬性:
AttributeDescriptionRequired
nametarget的名字Yes
depends用逗號分隔的target的名字列表,也就是依賴表。No
if執(zhí)行target所需要設(shè)定的屬性名。No
unless執(zhí)行target需要清除設(shè)定的屬性名。No
description關(guān)于target功能的簡短描述。No
3.3Tasks
一個task是一段可執(zhí)行的代碼。
一個task可以有多個屬性(如果你愿意的話,可以將其稱之為變量)。屬性只可能包含對property的引用。這些引用會在task執(zhí)行前被解析。
下面是Task的一般構(gòu)造形式:
<nameattribute1=”value1″attribute2=”value2″…/>
這里name是task的名字,attributeN是屬性名,valueN是屬性值。
有一套內(nèi)置的(built-in)task,以及一些可選task,但你也可以編寫自己的task。
所有的task都有一個task名字屬性。Ant用屬性值來產(chǎn)生日志信息。
可以給task賦一個id屬性:
<tasknameid=”taskID”…/>
這里taskname是task的名字,而taskID是這個task的唯一標(biāo)識符。通過這個標(biāo)識符,你可以在腳本中引用相應(yīng)的task。例如,在腳本中你可以這樣:
<script…>
task1.setFoo(“bar”);
</script>
設(shè)定某個task實(shí)例的foo屬性。在另一個task中(用java編寫),你可以利用下面的語句存取相應(yīng)的實(shí)例。
project.getReference(“task1”).
注意1:如果task1還沒有運(yùn)行,就不會被生效(例如:不設(shè)定屬性),如果你在隨后配置它,你所作的一切都會被覆蓋。
注意2:未來的Ant版本可能不會兼容這里所提的屬性,因?yàn)楹苡锌赡芨緵]有task實(shí)例,只有proxies。
3.4Properties
一個project可以有很多的properties。可以在buildfile中用propertytask來設(shè)定,或在Ant之外設(shè)定。一個 property有一個名字和一個值。property可用于task的屬性值。這是通過將屬性名放在”${“和”}”之間并放在屬性值的位置來實(shí)現(xiàn)的。例如如果有一個propertybuilddir的值是”build”,這個property就可用于屬性值:${builddir} /classes。這個值就可被解析為build/classes。
內(nèi)置屬性
如果你使用了<property>task定義了所有的系統(tǒng)屬性,Ant允許你使用這些屬性。例如,${os.name}對應(yīng)操作系統(tǒng)的名字。
要想得到系統(tǒng)屬性的列表可參考theJavadocofSystem.getProperties。
除了Java的系統(tǒng)屬性,Ant還定義了一些自己的內(nèi)置屬性:
basedirproject基目錄的絕對路徑(與<project>的basedir屬性一樣)。
ant.filebuildfile的絕對路徑。
ant.versionAnt的版本。
ant.project.name當(dāng)前執(zhí)行的project的名字;由<project>的name屬性設(shè)定.
ant.java.versionAnt檢測到的JVM的版本;目前的值有”1.1″,“1.2”,“1.3”and“1.4”.
例子
<projectname=”MyProject”default=”dist”basedir=”.”>
<!–setglobalpropertiesforthisbuild–>
<propertyname=”src”value=”.”/>
<propertyname=”build”value=”build”/>
<propertyname=”dist”value=”dist”/>
<targetname=”init”>
<!–Createthetimestamp–>
<tstamp/>
<!–Createthebuilddirectorystructureusedbycompile–>
<mkdirdir=”${build}”/>
</target>
<targetname=”compile”depends=”init”>
<!–Compilethejavacodefrom${src}into${build}–>
<javacsrcdir=”${src}”destdir=”${build}”/>
</target>
<targetname=”dist”depends=”compile”>
<!–Createthedistributiondirectory–>
<mkdirdir=”${dist}/lib”/>
<!–Puteverythingin${build}intotheMyProject-${DSTAMP}.jarfile–>
<jarjarfile=”${dist}/lib/MyProject-${DSTAMP}.jar”basedir=”${build}”/>
</target>
<targetname=”clean”>
<!–Deletethe${build}and${dist}directorytrees–>
<deletedir=”${build}”/>
<deletedir=”${dist}”/>
</target>
</project>
3.5Path-likeStructures
你可以用”:”和”;”作為分隔符,指定類似PATH和CLASSPATH的引用。Ant會把分隔符轉(zhuǎn)換為當(dāng)前系統(tǒng)所用的分隔符。
當(dāng)需要指定類似路徑的值時,可以使用嵌套元素。一般的形式是
<classpath>
<pathelementpath=”${classpath}”/>
<pathelementlocation=”lib/helper.jar”/>
</classpath>
location屬性指定了相對于project基目錄的一個文件和目錄,而path屬性接受逗號或分號分隔的一個位置列表。path屬性一般用作預(yù)定義的路徑--其他情況下,應(yīng)該用多個location屬性。
為簡潔起見,classpath標(biāo)簽支持自己的path和location屬性。所以:
<classpath>
<pathelementpath=”${classpath}”/>
</classpath>
可以被簡寫作:
<classpathpath=”${classpath}”/>
也可通過<fileset>元素指定路徑。構(gòu)成一個fileset的多個文件加入path-likestructure的順序是未定的。
<classpath>
<pathelementpath=”${classpath}”/>
<filesetdir=”lib”>
<includename=”**/*.jar”/>
</fileset>
<pathelementlocation=”classes”/>
</classpath>
上面的例子構(gòu)造了一個路徑值包括:${classpath}的路徑,跟著lib目錄下的所有jar文件,接著是classes目錄。
如果你想在多個task中使用相同的path-likestructure,你可以用<path>元素定義他們(與target同級),然后通過id屬性引用--參考Referencs例子。
path-likestructure可能包括對另一個path-likestructurede的引用(通過嵌套<path>元素):
<pathid=”base.path”>
<pathelementpath=”${classpath}”/>
<filesetdir=”lib”>
<includename=”**/*.jar”/>
</fileset>
<pathelementlocation=”classes”/>
</path>
<pathid=”tests.path”>
<pathrefid=”base.path”/>
<pathelementlocation=”testclasses”/>
</path>
前面所提的關(guān)于<classpath>的簡潔寫法對于<path>也是有效的,如:
<pathid=”tests.path”>
<pathrefid=”base.path”/>
<pathelementlocation=”testclasses”/>
</path>
可寫成:
<pathid=”base.path”path=”${classpath}”/>
命令行變量
有些task可接受參數(shù),并將其傳遞給另一個進(jìn)程。為了能在變量中包含空格字符,可使用嵌套的arg元素。
AttributeDescriptionRequired
value一個命令行變量;可包含空格字符。只能用一個
line空格分隔的命令行變量列表。
file作為命令行變量的文件名;會被文件的絕對名替代。
path一個作為單個命令行變量的path-like的字符串;或作為分隔符,Ant會將其轉(zhuǎn)變?yōu)樘囟ㄆ脚_的分隔符。
例子
<argvalue=”-l-a”/>
是一個含有空格的單個的命令行變量。
<argline=”-l-a”/>
是兩個空格分隔的命令行變量。
<argpath=”/dir;/dir2:/dir3″/>
是一個命令行變量,其值在DOS系統(tǒng)上為/dir;/dir2;/dir3;在Unix系統(tǒng)上為/dir:/dir2:/dir3。
References
buildfile元素的id屬性可用來引用這些元素。如果你需要一遍遍的復(fù)制相同的XML代碼塊,這一屬性就很有用--如多次使用<classpath>結(jié)構(gòu)。
下面的例子:
<project…>
<target…>
<rmic…>
<classpath>
<pathelementlocation=”lib/”/>
<pathelementpath=”${java.class.path}/”/>
<pathelementpath=”${additional.path}”/>
</classpath>
</rmic>
</target>
<target…>
<javac…>
<classpath>
<pathelementlocation=”lib/”/>
<pathelementpath=”${java.class.path}/”/>
<pathelementpath=”${additional.path}”/>
</classpath>
</javac>
</target>
</project>
可以寫成如下形式:
<project…>
<pathid=”project.class.path”>
<pathelementlocation=”lib/”/>
<pathelementpath=”${java.class.path}/”/>
<pathelementpath=”${additional.path}”/>
</path>
<target…>
<rmic…>
<classpathrefid=”project.class.path”/>
</rmic>
</target>
<target…>
<javac…>
<classpathrefid=”project.class.path”/>
</javac>
</target>
</project>
所有使用PatternSets,FileSets或path-likestructures嵌套元素的task也接受這種類型的引用。
4.1File(Directory)類
4.1.1Mkdir
?創(chuàng)建一個目錄,如果他的父目錄不存在,也會被同時創(chuàng)建。
?例子:
<mkdirdir=”build/classes”/>
?說明:如果build不存在,也會被同時創(chuàng)建
4.1.2Copy
?拷貝一個(組)文件、目錄
?例子:
1.拷貝單個的文件:
<copyfile=”myfile.txt”tofile=”mycopy.txt”/>
2.拷貝單個的文件到指定目錄下
<copyfile=”myfile.txt”todir=”../some/other/dir”/>
3.拷貝一個目錄到另外一個目錄下
<copytodir=”../new/dir”>
<filesetdir=”src_dir”/>
</copy>
4.拷貝一批文件到指定目錄下
<copytodir=”../dest/dir”>
<filesetdir=”src_dir”>
<excludename=”**/*.java”/>
</fileset>
</copy>
<copytodir=”../dest/dir”>
<filesetdir=”src_dir”excludes=”**/*.java”/>
</copy>
5.拷貝一批文件到指定目錄下,將文件名后增加。Bak后綴
<copytodir=”../backup/dir”>
<filesetdir=”src_dir”/>
<mappertype=”glob”from=”*”to=”*.bak”/>
</copy>
6.拷貝一組文件到指定目錄下,替換其中的@標(biāo)簽@內(nèi)容
<copytodir=”../backup/dir”>
<filesetdir=”src_dir”/>
<filterset>
<filtertoken=”TITLE”value=”FooBar”/>
</filterset>
</copy>
4.1.3Delete
?刪除一個(組)文件或者目錄
?例子
1.刪除一個文件
<deletefile=”/lib/ant.jar”/>
2.刪除指定目錄及其子目錄
<deletedir=”lib”/>
3.刪除指定的一組文件
<delete>
<filesetdir=”.”includes=”**/*.bak”/>
</delete>
4.刪除指定目錄及其子目錄,包括他自己
<deleteincludeEmptyDirs=”true”>
<filesetdir=”build”/>
</delete>
4.1.4Move
?移動或重命名一個(組)文件、目錄
?例子:
1.移動或重命名一個文件
<movefile=”file.orig”tofile=”file.moved”/>
2.移動或重命名一個文件到另一個文件夾下面
<movefile=”file.orig”todir=”dir/to/move/to”/>
3.將一個目錄移到另外一個目錄下
<movetodir=”new/dir/to/move/to”>
<filesetdir=”src/dir”/>
</move>
4.將一組文件移動到另外的目錄下
<movetodir=”some/new/dir”>
<filesetdir=”my/src/dir”>
<includename=”**/*.jar”/>
<excludename=”**/ant.jar”/>
</fileset>
</move>
5.移動文件過程中增加。Bak后綴
<movetodir=”my/src/dir”>
<filesetdir=”my/src/dir”>
<excludename=”**/*.bak”/>
</fileset>
<mappertype=”glob”from=”*”to=”*.bak”/>
</move>
4.2Java相關(guān)
4.2.1Javac
?編譯java原代碼
?例子
1.<javacsrcdir=”${src}”
destdir=”${build}”
classpath=”xyz.jar”
debug=”on”
/>
編譯${src}目錄及其子目錄下的所有。Java文件,。Class文件將放在${build}指定的目錄下,classpath表示需要用到的類文件或者目錄,debug設(shè)置為on表示輸出debug信息
2.<javacsrcdir=”${src}:${src2}”
destdir=”${build}”
includes=”mypackage/p1/**,mypackage/p2/**”
excludes=”mypackage/p1/testpackage/**”
classpath=”xyz.jar”
debug=”on”
/>
編譯${src}和${src2}目錄及其子目錄下的所有。Java文件,但是package/p1/**,mypackage/p2/**將被編譯,而 mypackage/p1/testpackage/**將不會被編譯。Class文件將放在${build}指定的目錄下,classpath表示需要用到的類文件或者目錄,debug設(shè)置為on表示輸出debug信息
3.<propertyname=”classpath”value=”.;./xml-apis.jar;../lib/xbean.jar;./easypo.jar”/>
<javacsrcdir=”${src}”
destdir=”${src}”
classpath=”${classpath}”
debug=”on”
/>
路徑是在property中定義的
4.2.2java
?執(zhí)行指定的java類
?例子:
1.<javaclassname=”test.Main”>
<classpath>
<pathelementlocation=”dist/test.jar”/>
<pathelementpath=”${java.class.path}”/>
</classpath>
</java>
classname中指定要執(zhí)行的類,classpath設(shè)定要使用的環(huán)境變量
2.<pathid=”project.class.path”>
<pathelementlocation=”lib/”/>
<pathelementpath=”${java.class.path}/”/>
<pathelementpath=”${additional.path}”/>
</path>
<target…>
<rmic…>
<classpathrefid=”project.class.path”/>
</rmic>
</target>
4.3打包相關(guān)
4.3.1jar
?將一組文件打包
?例子:
1.<jardestfile=”${dist}/lib/app.jar”basedir=”${build}/classes”/>
將${build}/classes下面的所有文件打包到${dist}/lib/app.jar中
2.<jardestfile=”${dist}/lib/app.jar”
basedir=”${build}/classes”
includes=”mypackage/test/**”
excludes=”**/Test.class”
/>
將${build}/classes下面的所有文件打包到${dist}/lib/app.jar中,但是包括mypackage/test/所有文件不包括所有的Test.class
3.<jardestfile=”${dist}/lib/app.jar”
basedir=”${build}/classes”
includes=”mypackage/test/**”
excludes=”**/Test.class”
manifest=”my.mf”
/>
manifest屬性指定自己的META-INF/MANIFEST.MF文件,而不是由系統(tǒng)生成
4.3.2war
?對Jar的擴(kuò)展,用于打包Web應(yīng)用
?例子:
?假設(shè)我們的文件目錄如下:
thirdparty/libs/jdbc1.jar
thirdparty/libs/jdbc2.jar
build/main/com/myco/myapp/Servlet.class
src/metadata/myapp.xml
src/html/myapp/index.html
src/jsp/myapp/front.jsp
src/graphics/images/gifs/small/logo.gif
src/graphics/images/gifs/large/logo.gif
?下面是我們的任務(wù)的內(nèi)容:
<wardestfile=”myapp.war”webxml=”src/metadata/myapp.xml”>
<filesetdir=”src/html/myapp”/>
<filesetdir=”src/jsp/myapp”/>
<libdir=”thirdparty/libs”>
<excludename=”jdbc1.jar”/>
</lib>
<classesdir=”build/main”/>
<zipfilesetdir=”src/graphics/images/gifs”
prefix=”images”/>
</war>
?完成后的結(jié)果:
WEB-INF/web.xml
WEB-INF/lib/jdbc2.jar
WEB-INF/classes/com/myco/myapp/Servlet.class
META-INF/MANIFEST.MF
index.html
front.jsp
images/small/logo.gif
images/large/logo.gif
4.3.3ear
?用于打包企業(yè)應(yīng)用
?例子
<eardestfile=”${build.dir}/myapp.ear”appxml=”${src.dir}/metadata/application.xml”>
<filesetdir=”${build.dir}”includes=”*.jar,*.war”/>
</ear>
4.4時間戳
在生成環(huán)境中使用當(dāng)前時間和日期,以某種方式標(biāo)記某個生成任務(wù)的輸出,以便記錄它是何時生成的,這經(jīng)常是可取的。這可能涉及編輯一個文件,以便插入一個字符串來指定日期和時間,或?qū)⑦@個信息合并到JAR或zip文件的文件名中。
這種需要是通過簡單但是非常有用的tstamp任務(wù)來解決的。這個任務(wù)通常在某次生成過程開始時調(diào)用,比如在一個init目標(biāo)中。這個任務(wù)不需要屬性,許多情況下只需<tstamp/>就足夠了。
tstamp不產(chǎn)生任何輸出;相反,它根據(jù)當(dāng)前系統(tǒng)時間和日期設(shè)置Ant屬性。下面是tstamp設(shè)置的一些屬性、對每個屬性的說明,以及這些屬性可被設(shè)置到的值的例子:
屬性說明例子
DSTAMP設(shè)置為當(dāng)前日期,默認(rèn)格式為yyyymmdd20031217
TSTAMP設(shè)置為當(dāng)前時間,默認(rèn)格式為hhmm1603
TODAY設(shè)置為當(dāng)前日期,帶完整的月份2003年12月17日
例如,在前一小節(jié)中,我們按如下方式創(chuàng)建了一個JAR文件:
<jardestfile=”package.jar”basedir=”classes”/>
在調(diào)用tstamp任務(wù)之后,我們能夠根據(jù)日期命名該JAR文件,如下所示:
<jardestfile=”package-${DSTAMP}.jar”basedir=”classes”/>
因此,如果這個任務(wù)在2003年12月17日調(diào)用,該JAR文件將被命名為package-20031217.jar。
還可以配置tstamp任務(wù)來設(shè)置不同的屬性,應(yīng)用一個當(dāng)前時間之前或之后的時間偏移,或以不同的方式格式化該字符串。所有這些都是使用一個嵌套的format元素來完成的,如下所示:
<tstamp>
<formatproperty=”OFFSET_TIME”
pattern=”HH:mm:ss”
offset=”10″unit=”minute”/>
</tstamp>
上面的清單將OFFSET_TIME屬性設(shè)置為距離當(dāng)前時間10分鐘之后的小時數(shù)、分鐘數(shù)和秒數(shù)。
用于定義格式字符串的字符與java.text.SimpleDateFormat類所定義的那些格式字符相同
4.5執(zhí)行SQL語句
?通過jdbc執(zhí)行SQL語句
?例子:
1.<sql
driver=”org.gjt.mm.mysql.Driver”
url=”jdbc:mysql://localhost:3306/mydb”
userid=”root”
password=”root”
src=”data.sql”
/>
2.<sql
driver=”org.database.jdbcDriver”
url=”jdbc:database-url”
userid=”sa”
password=”pass”
src=”data.sql”
rdbms=”oracle”
version=”8.1.”
>
</sql>
只有在oracle、版本是8.1的時候才執(zhí)行
4.6發(fā)送郵件
?使用SMTP服務(wù)器發(fā)送郵件
?例子:
<mailmailhost=”smtp.myisp.com”mailport=”1025″subject=”Testbuild”>
<fromaddress=”me@myisp.com”/>
<toaddress=”all@xyz.com”/>
<message>The${buildname}nightlybuildhascompleted</message>
<filesetdir=”dist”>
<includesname=”**/*.zip”/>
</fileset>
</mail>
?mailhost:SMTP服務(wù)器地址
?mailport:服務(wù)器端口
?subject:主題
?from:發(fā)送人地址
?to:接受人地址
?message:發(fā)送的消息
?fileset:設(shè)置附件
====================================================================
在ANT 出現(xiàn)之前,編譯和部署Java應(yīng)用需要使用包括特定平臺的腳本、Make文件、不同的IDE以及手工操作等組成的大雜燴?,F(xiàn)在,幾乎所有的開源Java項(xiàng)目都在使用Ant,許多公司的開發(fā)項(xiàng)目也在使用Ant。Ant的大量使用,也自然帶來了對總結(jié)Ant最佳實(shí)踐的迫切需求。
本文總結(jié)了我喜好的Ant最佳實(shí)踐,很多是從親身經(jīng)歷的項(xiàng)目錯誤,或從其他開發(fā)者的“恐怖”故事中得到的靈感的。比如,有人告訴我有個項(xiàng)目將XDoclet生成的代碼放入鎖定文件的版本控制工具中。單開發(fā)者修改源代碼時,他必須記住手工檢出(Checkout)并鎖定所有將要重生成的文件。然后,手工運(yùn)行代碼生成器,當(dāng)他能夠讓Ant編譯代碼時,這一方法還存在一些問題:
生成的代碼無法存儲在版本控制系統(tǒng)中
Ant(本案例中是Xdoclet)應(yīng)該自動確定下一次構(gòu)建涉及的源文件,而不應(yīng)由程序員人工確定。
Ant的構(gòu)建文件應(yīng)該定義好正確的任務(wù)依賴關(guān)系,這樣程序員不必按照特定順序調(diào)用任務(wù)。
當(dāng)我開始一個新項(xiàng)目時,我首先編寫Ant構(gòu)建文件。文件定義構(gòu)建的過程,并為團(tuán)隊(duì)中的每個程序員都使用。本文所有的最佳實(shí)踐假設(shè)Ant構(gòu)建文件是一個必須精心編寫的重要文件,它應(yīng)在版本控制系統(tǒng)中得到維護(hù),并定期進(jìn)行重構(gòu)。下面是我的十五大Ant最佳實(shí)踐。
1.采用一致的編碼規(guī)范
Ant用戶不管是喜歡還是痛恨XML構(gòu)建文件的語法,都愿意跳進(jìn)這一迷人的爭論中。讓我們先看一些保持XML構(gòu)建文件簡潔的方法。
首先,也是最重要的,化費(fèi)時間格式化你的XML讓它看上去很清晰。不過XML是否美觀,Ant都可以工作。但是丑陋的XML很難讀懂。倘若你在任務(wù)之間留出空行,有規(guī)則的縮進(jìn),每行文字不超過90列,那么XML令人驚訝的易讀。再加上好的編輯器或IDE高亮相應(yīng)的語句,你就不會有如何閱讀的麻煩。同樣,精選有意義明確、容易讀懂的詞匯來命名任務(wù)和屬性。比如,dir.reports就比rpts好。并不需要特定的編碼規(guī)范,只要有一種規(guī)范并堅(jiān)持使用就好。
2.將build.xml放在項(xiàng)目根目錄中
Ant構(gòu)建文件build.xml可以放在如何位置,但是放在項(xiàng)目頂層目錄中可以保持項(xiàng)目簡潔。這是最普遍的規(guī)范,使開發(fā)者能夠在根目錄找到它。同時,也能夠容易了解項(xiàng)目中不同目錄之間的邏輯關(guān)系。以下是一個典型的項(xiàng)目層次:
[rootdir]|build.xml+–src+–lib(包含第三方JAR包)+–build(由build任務(wù)生成)+–dist(由build任務(wù)生成)
當(dāng)build.xml在頂級目錄時,倘若你在項(xiàng)目某個子目錄中,只要輸入:ant-findcompile命令,不需要改變工作目錄就能夠以命令行方式編譯代碼。參數(shù)-find告訴Ant尋找存在于上級目錄中的build.xml并執(zhí)行。
3.使用單一構(gòu)建文件
有人喜歡將一個大項(xiàng)目分解到幾個小的構(gòu)建文件,每個構(gòu)建文件分擔(dān)整個構(gòu)建過程的一小部分工作。但是應(yīng)該認(rèn)識到,將構(gòu)建文件分割會增加對整個構(gòu)建過程的理解難度。要注意在單一構(gòu)建文件能夠清楚表現(xiàn)構(gòu)建層次的情況下,不要過工程化(over-engineer)。
即使你把項(xiàng)目劃分為多個構(gòu)建文件,也應(yīng)使程序員能夠在項(xiàng)目根目錄下找到核心build.xml。盡管該文件只是將實(shí)際構(gòu)建工作委派給下級構(gòu)建文件,也應(yīng)保證該文件可用。
4.提供良好的幫助說明
應(yīng)盡量使構(gòu)建文件自文檔化。增加任務(wù)描述是最簡單的方法。當(dāng)你輸入ant-projecthelp時,你就可以看到帶有描述的任務(wù)清單。比如,你可以這樣定義任務(wù):
<targetname=”compile”description=”Compilescode,outputgoestothebuilddir.”>
最簡單的規(guī)則是對所有你希望程序員通過命令行直接調(diào)用的任務(wù)都加上描述。對于一般用來執(zhí)行中間處理過程的內(nèi)部任務(wù),比如生成代碼或建立輸出目錄等,就無法使用描述屬性。
這時,可以通過在構(gòu)建文件中加入XML注釋來處理?;蛘邔iT定義一個help任務(wù),當(dāng)程序員輸入anthelp時來顯示詳細(xì)的使用說明。
<targetname=”help”description=”Displaydetailedusageinformation”><echo>Detailedhelp…</echo></target>
5.提供清空任務(wù)
每個構(gòu)建文件都應(yīng)包含一個清空任務(wù),刪除所有生成的文件和目錄,使系統(tǒng)回到構(gòu)建文件執(zhí)行前的初始狀態(tài)。執(zhí)行清空任務(wù)后還存在的文件應(yīng)處在版本控制系統(tǒng)的管理下。
比如:
<targetname=”clean”description=”Destroysallgeneratedfilesanddirs.”><deletedir=”${dir.build}”/><deletedir=”${dir.dist}”/></target>
除非是在產(chǎn)生整個系統(tǒng)版本的特殊任務(wù)中,否則不要自動調(diào)用clean任務(wù)。當(dāng)程序員僅僅執(zhí)行編譯任務(wù)或其他任務(wù)時,他們不需要構(gòu)建文件事先執(zhí)行即令人討厭有沒有必要的清空任務(wù)。要相信程序員能夠確定何時需要清空所有文件。
6.使用ANT管理任務(wù)從屬關(guān)系
假設(shè)你的應(yīng)用由SwingGUI組件、Web界面、EJB層和公共應(yīng)用代碼組成。在大型系統(tǒng)中,你需要清晰地定義Java包屬于系統(tǒng)的哪一層。否則如何一點(diǎn)修改都要重新編譯成千上百個文件。任務(wù)從屬關(guān)系管理差會導(dǎo)致過度復(fù)雜而脆弱的系統(tǒng)。改變GUI面板的設(shè)計(jì)不應(yīng)造成Servlet和EJB的重編譯。
當(dāng)系統(tǒng)變得龐大后,稍不注意就可能將依賴于客戶端的代碼引入到服務(wù)端。這是因?yàn)镮DE在編譯文件時使用單一的classpath。Ant讓你更有效地控制構(gòu)建活動。
設(shè)計(jì)你的構(gòu)建文件編譯大型項(xiàng)目的步驟:首先,編譯公共應(yīng)用代碼,將編譯結(jié)果打成JAR包文件。然后,編譯上一層的項(xiàng)目代碼,編譯時依靠第一步產(chǎn)生的JAR文件。不斷重復(fù)這一過程,直到最高層的代碼編譯完成。
分步構(gòu)建強(qiáng)化了任務(wù)從屬關(guān)系管理。如果你工作在底層Java框架上,引用高層的GUI模板組件,這時代碼不需要編譯。這是由于構(gòu)建文件在編譯底層框架時,在源路徑中沒有包含高層GUI面板組件的代碼。
7.定義并重用文件路徑
如果文件路徑在一個地方集中定義,并在整個構(gòu)建文件中得到重用,那么構(gòu)建文件更易于理解。以下是這樣做的一個例子:
<projectname=”sample”default=”compile”basedir=”.”><pathid=”classpath.common”><pathelementlocation=”${jdom.jar.withpath}”/>…etc</path><pathid=”classpath.client”><pathelementlocation=”${guistuff.jar.withpath}”/><pathelementlocation=”${another.jar.withpath}”/><!–reusethecommonclasspath–><pathrefid=”classpath.common”/></path><targetname=”compile.common”depends=”prepare”><javacdestdir=”${dir.build}”srcdir=”${dir.src}”><classpathrefid=”classpath.common”/><includename=”com/oreilly/common/**”/></javac></target></project>
當(dāng)項(xiàng)目不斷增長,構(gòu)建日益復(fù)雜時,這一技術(shù)越發(fā)體現(xiàn)出其價值。你可能為編譯不同層次的應(yīng)用定義各自的文件路徑,比如運(yùn)行單元測試的、運(yùn)行應(yīng)用程序的、運(yùn)行 Xdoclet的、生成JavaDocs的等等不同路徑。這種組件化路徑定義的方法比為每個任務(wù)單獨(dú)定義路徑要優(yōu)越得多。否則,很容易丟失任務(wù)任務(wù)從屬關(guān)系的軌跡。
8.定義恰當(dāng)?shù)娜蝿?wù)參數(shù)關(guān)系
假設(shè)dist任務(wù)從屬于jar任務(wù),那么哪個任務(wù)從屬于compile任務(wù),哪個任務(wù)從屬于prepare任務(wù)呢?Ant構(gòu)建文件最終定義了任務(wù)的從屬關(guān)系圖,它必須被仔細(xì)地定義和維護(hù)。應(yīng)該定期檢查任務(wù)的從屬關(guān)系以保證構(gòu)建工作得到正確執(zhí)行。大的構(gòu)建文件隨著時間推移趨向于增加更多的任務(wù),所以到最后由于不必要的從屬關(guān)系導(dǎo)致構(gòu)建工作非常困難。比如,你可能發(fā)現(xiàn)在程序員只是需要編譯一些沒有使用EJB的GUI代碼時,重新生成EJB代碼。
以“優(yōu)化”的名義忽略任務(wù)的從屬關(guān)系是另一種常見的錯誤。這種錯誤迫使程序員為了得到恰當(dāng)?shù)慕Y(jié)果必須記住并按照特定的順序調(diào)用一串任務(wù)。更好的做法是:提供描述清晰的公共任務(wù),這些任務(wù)包含正確的任務(wù)從屬關(guān)系;另外提供一套“專家”任務(wù)讓你能夠手工執(zhí)行個別的構(gòu)建步驟,這些任務(wù)不提供完整的構(gòu)建過程,但是讓那些專家在快速而惱人的編碼期間跳過某些步驟
9.使用配置屬性
任何需要配置或可能發(fā)生變化的信息都應(yīng)作為Ant屬性定義下來。對于在構(gòu)建文件中多次出現(xiàn)的值也同樣處理。屬性既可以在構(gòu)建文件頭部定義,也可以為了更好的靈活性而在單獨(dú)的屬性文件中定義。以下是在構(gòu)建文件中定義屬性的樣式:
<projectname=”sample”default=”compile”basedir=”.”><propertyname=”dir.build”value=”build”/><propertyname=”dir.src”value=”src”/><propertyname=”jdom.home”value=”../java-tools/jdom-b8″/><propertyname=”jdom.jar”value=”jdom.jar”/><propertyname=”jdom.jar.withpath”value=”${jdom.home}/build/${jdom.jar}”/>etc…</project>
或者你可以使用屬性文件:
<projectname=”sample”default=”compile”basedir=”.”><propertyfile=”sample.properties”/>etc…</project>
在屬性文件sample.properties中:
dir.build=builddir.src=srcjdom.home=../java-tools/jdom-b8jdom.jar=jdom.jarjdom.jar.withpath=${jdom.home}/build/${jdom.jar}
用一個獨(dú)立的文件定義屬性是有好處的,它可以清晰地定義構(gòu)建中的可配置部分。另外,在開發(fā)者工作在不同操作系統(tǒng)的情況下,你可以在不同的平臺上提供該文件的不同版本。
10.保持構(gòu)建過程獨(dú)立
為了最大限度的擴(kuò)展性,不要應(yīng)用外部路徑和庫文件。最重要的是不要依賴于程序員的CLASSPATH設(shè)置。取而代之的是,在構(gòu)建文件中使用相對路徑并定義自己的路徑。如果你引用了絕對路徑如C:/java/tools,其他開發(fā)者未必使用與你相同的目錄結(jié)構(gòu),所以就無法使用你的構(gòu)建文件
如果你部署開發(fā)源碼項(xiàng)目,應(yīng)該提供包括所有需要的JAR文件的發(fā)行版本,當(dāng)然是在遵守許可協(xié)議的基礎(chǔ)上。對于內(nèi)部項(xiàng)目,相關(guān)的JAR文件都應(yīng)在版本控制系統(tǒng)的管理中,并撿出到大家都知道的位置。
當(dāng)你不得不應(yīng)用外部路徑時,應(yīng)將路徑定義為屬性。使程序員能夠涌適合他們自己的機(jī)器的參數(shù)重載這些屬性。你也可以使用以下語法引用環(huán)境變量:
<propertyenvironment=”env”/><propertyname=”dir.jboss”value=”${env.JBOSS_HOME}”/>
11.使用版本控制系統(tǒng)
構(gòu)建文件是一個重要的文件,應(yīng)該象代碼一樣進(jìn)行版本控制。當(dāng)你標(biāo)記你的代碼時,也應(yīng)用同樣的標(biāo)簽標(biāo)記構(gòu)建文件。這樣當(dāng)你需要回溯構(gòu)建舊版本的軟件時,能夠使用相對應(yīng)的舊版本構(gòu)建文件。
除構(gòu)建文件之外,你還應(yīng)在版本控制中維護(hù)第三方JAR文件。同樣,這使你能夠重新構(gòu)建舊版本的軟件。這也能夠更容易保證所有開發(fā)者擁有一致的JAR文件,因?yàn)樗麄兌际峭瑯?gòu)建文件一起從版本控制系統(tǒng)中撿出的。
通常應(yīng)避免在版本控制系統(tǒng)中存放構(gòu)建輸出品。倘若你的源代碼很好地得到了版本控制,那么通過構(gòu)建過程你能夠重新生成任何版本的產(chǎn)品。
12.把Ant作為“最小公分母”
假設(shè)你的開發(fā)團(tuán)隊(duì)使用IDE,為什么要為程序員通過點(diǎn)擊圖標(biāo)就能夠構(gòu)建整個應(yīng)用而煩惱呢?
IDE 的問題在團(tuán)隊(duì)中是一個關(guān)于一致性和重現(xiàn)性的問題。幾乎所有的IDE設(shè)計(jì)初衷都是為了提高程序員的個人生產(chǎn)率,而不是開發(fā)團(tuán)隊(duì)的持續(xù)構(gòu)建。典型的IDE要求每個程序員定義自己的項(xiàng)目文件。程序員可能擁有不同的目錄結(jié)構(gòu),可能使用不同版本的庫文件,還可能工作在不同的平臺上。這將導(dǎo)致出現(xiàn)這種情況:在A那里運(yùn)行良好的代碼,到B那里就無法運(yùn)行。
不管你的開發(fā)團(tuán)隊(duì)使用何種IDE,一定要建立所有程序員都能夠使用的Ant構(gòu)建文件。要建立一個程序員在將新代碼提交版本控制系統(tǒng)前必須執(zhí)行Ant構(gòu)建文件的規(guī)則。這將確保代碼是經(jīng)過同一個Ant構(gòu)建文件構(gòu)建的。當(dāng)出現(xiàn)問題時,要使用項(xiàng)目標(biāo)準(zhǔn)的 Ant構(gòu)建文件,而不是通過某個IDE來執(zhí)行一個干凈的構(gòu)建。
程序員可以自由選擇任何他們習(xí)慣使用的IDE。但是Ant應(yīng)作為公共基線以保證永遠(yuǎn)是可構(gòu)建的。
13.使用zipfileset屬性
人們經(jīng)常使用Ant產(chǎn)生WAR、JAR、ZIP和EAR文件。這些文件通常都要求有一個特定的內(nèi)部目錄結(jié)構(gòu),但其往往與你的源代碼和編譯環(huán)境的目錄結(jié)構(gòu)不匹配。
一個最常用的方法是寫一個Ant任務(wù)按照期望的目錄結(jié)構(gòu)把一大堆文件拷貝到臨時目錄中,然后生成壓縮文件。這不是最有效的方法。使用zipfileset屬性是更好的解決方案。它讓你從任何位置選擇文件,然后把它們按照不同目錄結(jié)構(gòu)放進(jìn)壓縮文件中。以下是一個例子:
<earearfile=”${dir.dist.server}/payroll.ear”appxml=”${dir.resources}/application.xml”><filesetdir=”${dir.build}”includes=”commonServer.jar”/><filesetdir=”${dir.build}”><includename=”payroll-ejb.jar”/></fileset><zipfilesetdir=”${dir.build}”prefix=”lib”><includename=”hr.jar”/><includename=”billing.jar”/></zipfileset><filesetdir=”.”><includename=”lib/jdom.jar”/><includename=”lib/log4j.jar”/><includename=”lib/ojdbc14.jar”/></fileset><zipfilesetdir=”${dir.generated.src}”prefix=”META-INF”><includename=”jboss-app.xml”/></zipfileset></ear>
在這個例子中,所有JAR文件都放在EAR文件包的lib目錄中。hr.jar和billing.jar是從構(gòu)建目錄拷貝過來的。因此我們使用zipfileset屬性把它們移動到EAR文件包內(nèi)部的lib目錄。prefix屬性指定了其在EAR文件中的目標(biāo)路徑。
14.運(yùn)行Clean構(gòu)建任務(wù)的測試
假設(shè)你的構(gòu)建文件中有clean和compile的任務(wù),執(zhí)行以下的測試。第一步,執(zhí)行antclean;第二步,執(zhí)行antcompile;第三步,再執(zhí)行antcompile。第三步應(yīng)該不作任何事情。如果文件再次被編譯,說明你的構(gòu)建文件有問題。
構(gòu)建文件應(yīng)該只在與輸出文件相關(guān)聯(lián)的輸入文件發(fā)生變化時,才應(yīng)該執(zhí)行任務(wù)。一個構(gòu)建文件在不必執(zhí)行諸如編譯、拷貝或其他工作任務(wù)的時候執(zhí)行這些等任務(wù)是低效的。當(dāng)項(xiàng)目規(guī)模增長時,即使是小的低效工作也會成為大的問題。
15.避免特定平臺的Ant包
不管什么原因,有人喜歡用簡單的、名稱叫做compile之類的批文件或腳本裝載他們的產(chǎn)品。當(dāng)你去看腳本的內(nèi)容,你會發(fā)現(xiàn)以下內(nèi)容:
antcompile
其實(shí)開發(fā)人員熟悉Ant,并且完全能夠自己鍵入antcompile。請不要僅僅為了調(diào)用Ant而使用特定平臺的腳本。這只會使其他人在首次使用你的腳本時,增加學(xué)習(xí)和理解的煩擾。除此之外,你不可能提供適用于每個操作系統(tǒng)的腳本,這是真正煩擾其他用戶的地方。
總結(jié)
太多的公司依靠手工方法和程序來編譯代碼和生成軟件發(fā)布版本。那些不使用Ant或類似工具定義構(gòu)建過程的開發(fā)團(tuán)隊(duì),花費(fèi)了令人驚異的時間來捕捉代碼編譯過程中出現(xiàn)的問題,這些在某些開發(fā)者那里編譯成功的代碼,到另一些開發(fā)者那里卻失敗了。
生成并維護(hù)構(gòu)建腳本不是一項(xiàng)迷人的工作,但卻是一項(xiàng)必需的工作。一個好的Ant構(gòu)建文件將使你集中到更喜歡的工作——寫代碼中!
無所不能的“螞蟻”–Ant
說他無所不能,好像有點(diǎn)夸張,但是用過Ant之后,感覺真的是只有想不到?jīng)]有作不到.Ant,原作者選擇他作為軟件名字的意思是指”令一個簡潔的工具”(Another Neat Tool),而這個真正的名字現(xiàn)在去很少為人所知,但這絲毫不影響他成為最優(yōu)秀的構(gòu)建工具.
現(xiàn)在開始我將進(jìn)入一個”螞蟻”的世界,通過例子,真真正正去了解他!
文章參考資料可以到http://www.manning.com/antbook去下載
Ant的最好學(xué)習(xí)資料<<使用Ant進(jìn)行Java開發(fā)>>
Ant的官方網(wǎng)站:http://ant.apache.org/
Ant的最新版本:Ant 1.6.5
本文所有的例子運(yùn)行的環(huán)境:JDK1.4.2,Ant1.6.2,eclipse3.0
一.使用Ant運(yùn)行Java程序
我們先從簡單的Hello學(xué)起,目錄結(jié)構(gòu)如下
project–
|src–
| |–org.ant.chapter1.Hello
|bin
|build.xml
以后的例子大多采用此目錄結(jié)構(gòu),特例會額外聲明
build.xml文件
<?xml version="1.0"?> <project name="project" default="run"> <target name="compile"> <javac destdir="bin" srcdir="src"></javac> </target> <target name="run" depends="compile"> <java classname="org.ant.chapter1.Hello"> </java> </target> </project> |
從結(jié)構(gòu)來看構(gòu)建文件很簡單,里面的內(nèi)容大家也一定能夠看得懂,可以看出Ant的核心任務(wù)就是target,一個Ant文件有多個target組成,而這些target之間,又有相互的依賴關(guān)系–depends,運(yùn)行的時候默認(rèn)運(yùn)行project中指定的target.
javac–編譯java文件 java–運(yùn)行java文件
使用eclipse中集成的Ant運(yùn)行build.xml文件(當(dāng)然,也可以將ANT_HOME加到Path中,在命令行中運(yùn)行)
Buildfile: D:/MyEclipse/workspace/sad/build.xml compile: run: [java] Working directory ignored when same JVM is used. [java] Could not find org.ant.chapter1.Hello. Make sure you have it in your classpath [java] at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:166) [java] at org.apache.tools.ant.taskdefs.Java.run(Java.java:705) [java] at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:177) [java] at org.apache.tools.ant.taskdefs.Java.execute(Java.java:83) [java] at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:275) [java] at org.apache.tools.ant.Task.perform(Task.java:364) [java] at org.apache.tools.ant.Target.execute(Target.java:341) [java] at org.apache.tools.ant.Target.performTasks(Target.java:369) [java] at org.apache.tools.ant.Project.executeTarget(Project.java:1214) [java] at org.eclipse.ant.internal.ui.antsupport.InternalAntRunner.run(InternalAntRunner.java:379) [java] at org.eclipse.ant.internal.ui.antsupport.InternalAntRunner.main(InternalAntRunner.java:135) BUILD SUCCESSFUL Total time: 703 milliseconds |
,java入門的經(jīng)典錯誤,ClassNotDefException,可見是classpath設(shè)置問題,而觀察得到compile成功運(yùn)行,所以我們在run-target里面加入classpath的配置
<?xml version="1.0"?> <project name="project" default="run"> <target name="compile"> <javac destdir="bin" srcdir="src"></javac> </target> <target name="run" depends="compile"> <java classname="org.ant.chapter1.Hello"> <classpath path="bin"></classpath> </java> </target> </project> |
運(yùn)行
Buildfile: D:/MyEclipse/workspace/sad/build.xml compile: run: [java] Hello World! BUILD SUCCESSFUL Total time: 672 milliseconds |
成功!!第一個Ant應(yīng)用完成,有人會說:用IDE運(yùn)行豈不是更簡單,但是你要知道運(yùn)行java程序只是Ant的一個小小的功能,后面我們會看到Ant的更強(qiáng)大的功能!
下一篇文章將介紹java程序運(yùn)行的擴(kuò)展及用Ant運(yùn)行tomcat!
java程序運(yùn)行的擴(kuò)展
1.帶有參數(shù)的應(yīng)用程序運(yùn)行
Ant在<java>任務(wù)中提供了<arg>元素,<arg>有四種屬性value,file,line,path
public class Hello {
public static void main(String[] args) {
System.out.println("Hello " + args[0]);
File file = new File(args[1]);
String[] filename = file.list();
for(int i = 0; i < filename.length; i++) {
System.out.println(filename[i]);
}
}
}
|
build.xml
<?xml version="1.0"?>
<project name="project" default="run">
<property name="run.classpath" value="bin"></property>
<target name="compile">
<javac destdir="bin" srcdir="src"></javac>
</target>
<target name="run" depends="compile">
<java classname="org.ant.chapter1.Hello">
<classpath path="${run.classpath}"></classpath>
<arg value="Ant"/>
<arg file="D:/rag"/>
</java>
</target>
</project>
|
Buildfile: D:/MyEclipse/workspace/sad/build.xml compile: run: [java] Hello Ant [java] hello.dat BUILD SUCCESSFUL Total time: 734 milliseconds |
2.控制新的JVM
一般的<java>任務(wù)都運(yùn)行在當(dāng)前的JVM中,單一些特定的情況下將Ant運(yùn)行在新的JVM下面,這時只需要將<java>中的一個屬性fork設(shè)置為true就可以了.
我們知道,java命令提供了許多的運(yùn)行參數(shù),用于指定JVM的屬性,同樣在Ant也提供相應(yīng)的屬性,看例子:
<?xml version="1.0"?>
<project name="project" default="run">
<property name="run.classpath" value="bin"></property>
<property name="Search.JVM.extra.args" value="-Xincgc"></property>
<target name="compile">
<javac destdir="bin" srcdir="src"></javac>
</target>
<target name="run" depends="compile">
<java classname="org.ant.chapter1.Hello" fork="true"
maxmemory="64m">
<classpath path="${run.classpath}"></classpath>
<jvmarg line="${Search.JVM.extra.args}"/>
<arg value="Ant"/>
<arg file="D:/rag"/>
</java>
</target>
</project>
|
3.運(yùn)行jar文件,使用failonerror處理錯誤
<java>同樣提供了運(yùn)行jar文件的屬性
MANIFEST.MF
Mainfest-Version: 1.0 Created-By: myth Sealed: false Main-Class: org.ant.chapter1.Hello |
build.xml
<?xml version="1.0"?>
<project name="project" default="run">
<property name="run.classpath" value="bin"></property>
<property name="Search.JVM.extra.args" value="-Xincgc"></property>
<target name="compile">
<javac destdir="bin" srcdir="src"></javac>
</target>
<target name="jar" depends="compile">
<jar destfile="test.jar" update="true"
manifest="MANIFEST.MF">
<fileset dir="bin">
<include name="**/*.class"/>
</fileset>
</jar>
</target>
<target name="run" depends="jar">
<java fork="true" maxmemory="64m" jar="test.jar">
<classpath path="${run.classpath}"></classpath>
<jvmarg line="${Search.JVM.extra.args}"/>
<arg value="Ant"/>
<arg file="D:/rag"/>
</java>
</target>
</project>
|
Buildfile: D:/MyEclipse/workspace/sad/build.xml compile: jar: [jar] Updating jar: D:/MyEclipse/workspace/sad/test.jar run: [java] Hello Ant [java] hello.dat BUILD SUCCESSFUL Total time: 875 milliseconds |
在某些情況下,我們不希望由于一些不重要的任務(wù)構(gòu)建失敗,而導(dǎo)致整個構(gòu)建的失敗,所以Ant提供了一個共同的屬性-failonerror,多數(shù)任務(wù)的默認(rèn)值為failοnerrοr=”true”,既當(dāng)此任務(wù)構(gòu)建失敗時,失敗信息會傳遞給控制臺,并導(dǎo)致build failed,failonerror只支持在新的JVM里運(yùn)行.
<target name="run" depends="jar">
<java fork="true" maxmemory="64m" jar="test.jar"
failοnerrοr="false" >
<classpath path="${run.classpath}"></classpath>
<jvmarg line="${Search.JVM.extra.args}"/>
<arg value="Ant"/>
<arg file="D:/rag"/>
</java>
</target>
|
Buildfile: D:/MyEclipse/workspace/sad/build.xml compile: jar: run: [java] java.lang.NullPointerException [java] at org.ant.chapter1.Hello.main(Hello.java:27) [java] Hello Ant [java] Exception in thread "main" [java] Java Result: 1 BUILD SUCCESSFUL Total time: 984 milliseconds |
可以看出雖然run構(gòu)建失敗,但是Ant還是執(zhí)行了,原來的jar文件,并且BUILD SUCCESSFUL!!
使用Ant運(yùn)行tomcat
Ant使用<exec>任務(wù)運(yùn)行本地程序,先看一個例子:
<?xml version="1.0"?> <project name="project" default="run"> <target name="run"> <exec executable="cmd"> <arg value="/C a.bat"/> </exec> </target> </project> |
a.bat
@echo off echo Hello >> a.txt |
運(yùn)行完后,會在根目錄生成a.txt文件,里面內(nèi)容為Hello
下面我們來運(yùn)行tomcat
<?xml version="1.0"?>
<project name="project" default="tomcat-start">
<property name="tomcat.dir" value="c:/Tomcat5"></property>
<target name="tomcat-start">
<exec dir="${tomcat.dir}/bin" executable="cmd">
<env key="CATALINA_HOME" path="${tomcat.dir}"/>
<arg value="/C startup.bat"/>
</exec>
</target>
<target name="tomcat-stop">
<exec dir="${tomcat.dir}/bin" executable="cmd">
<env key="CATALINA_HOME" path="${tomcat.dir}"/>
<arg value="/c shutdown.bat"/>
</exec>
</target>
</project>
|
成功!!
四.使用Ant進(jìn)行Junit測試
我們除了使用java來直接運(yùn)行junit之外,我們還可以使用junit提供的junit task與ant結(jié)合來運(yùn)行。涉及的幾個主要的ant task如下:
l <junit>,定義一個junit task
l <batchtest>,位于<junit>中,運(yùn)行多個TestCase
l <test>,位于<junit>中,運(yùn)行單個TestCase
l <formatter>,位于<junit>中,定義一個測試結(jié)果輸出格式
l <junitreport>,定義一個junitreport task
l <report>,位于<junitreport>中,輸出一個junit report
運(yùn)行Junit需要jakarta-ant-1.4-optional.jar和Junit.jar包,因?yàn)檫@兩個包用于支持ant task–<junit>的,所以不能在build.xml文件中加載,需要將他們放到ANT_HOME中去.使用eclipse可以按照一下步驟加入:
Windows-Preference-Ant-Runtime-Ant Home Entries
下面看一個Junit測試的例子:
|
可以看出Junit的使用基本和java差不多, printsummary允許輸出junit信息,當(dāng)然Ant提供formatter屬性支持多樣化的junit信息輸出.Ant包含三種形式的formatter:
brief:以文本格式提供測試失敗的詳細(xì)內(nèi)容;
plain:以文本格式提供測試失敗的詳細(xì)內(nèi)容以及每個測試的運(yùn)行統(tǒng)計(jì);
xml:以xml格式提供擴(kuò)展的詳細(xì)內(nèi)容,包括正在測試時的Ant特性,系統(tǒng)輸出,以及每個測試用 例的系統(tǒng)錯誤.
使用formatter時建議將printsummary關(guān)閉,因?yàn)樗赡軐ormatter的生成結(jié)果產(chǎn)生影響,并多生成一份同樣的輸出.當(dāng)然我們可以使用formatter將輸出結(jié)果顯示在console中:
<formatter type=”brief” usefile=”false”/>
Junit支持多個formatter同時存在:
<formatter type=”brief” usefile=”false”/>
<formatter type=”xml”/>
使用xml我們可以得到擴(kuò)展性更強(qiáng)的信息輸出,這時在<test>中要設(shè)定todir來指定xml的輸出路徑.
在通常情況下我們不可能一個一個來處理junit,所以Ant提供了<batchtest>,可以在他里面嵌套文件集(fileset)以包含全部的測試用例.
對于大量的用例,使用控制臺輸出,或者使用文件或xml文件來作為測試結(jié)果都是不合適的,Ant提供了<junitreport>任務(wù)使用XSLT將xml文件轉(zhuǎn)換為HTML報告.該任務(wù)首先將生成的XML文件整合成單一的XML文件,然后再對他進(jìn)行轉(zhuǎn)換,這個整合的文件默認(rèn)情況下被命名為:TESTS-TestSuites.xml.
|
<report>元素指示轉(zhuǎn)換過程中生成有框架(frames)或者無框架的類似與javadoc格式的文件,并保存到todir所在的目錄下面.(由于xalan對于JDK1.4以上的版本存在問題,所以要生成HTML文件需要以下步驟:現(xiàn)在最新的xalan,在%JAVA_HOME%/jre/lib中建立文件夾endorsed.將xalan中的jar文件copy到里面).
下面看一個完整的例子:
|
生成的文檔:
點(diǎn)擊Properties超鏈接會彈出一個窗口顯示在測試運(yùn)行時全部的Ant特性,這對于跟蹤由環(huán)境和配置造成的失敗是非常便利的!
五.使用Ant運(yùn)行本地程序
1.使用Ant運(yùn)行windows的批處理文件
要在Ant內(nèi)運(yùn)行一個外部程序,應(yīng)使用<exec>任務(wù).它允許你執(zhí)行下列操作:
l 指定程序名和要傳入的參數(shù).
l 命名運(yùn)行目錄.
l 使用failonerror標(biāo)志來控制當(dāng)應(yīng)用程序失敗時是否停止構(gòu)建.
l 指定一個最大程序持續(xù)時間,時間超過則中止程序.任務(wù)在這時被認(rèn)為是失敗,但是至少構(gòu)建會中止,而不是掛起,這對于自動構(gòu)建是至關(guān)重要的.
l 將輸出存到一個文件或特性.
l 指定java調(diào)用本地程序時需要預(yù)先設(shè)定的環(huán)境變量.
下面來看一個例子:
批處理文件:
Test.bat
|
build.xml
|
使用executable元素標(biāo)記指定使用的命令,具體用法可以在命令行下面輸入help cmd查看.如果你希望在運(yùn)行批處理發(fā)生錯誤時中止構(gòu)建需要設(shè)定failοnerrοr=”on”.加入你的外部程序在某個時刻掛起,也許是在與遠(yuǎn)程站點(diǎn)對話,而你不希望構(gòu)建永遠(yuǎn)被掛起,Ant提供了timeout這個屬性,他是一個以毫秒為單位的數(shù)字.下面看一下如何使用Ant來運(yùn)行tomcat.
啟動tomcat需要兩個環(huán)境變量CATALINA_HOME, JAVA_HOME,如果你在環(huán)境變量中已經(jīng)設(shè)定,在Ant中就不需要進(jìn)行處理,如果沒有需要使用<env>屬性來設(shè)定,你也可以使用<env>屬性覆蓋你以前的環(huán)境變量.
|
2.使用Ant運(yùn)行shell文件
由于windowsXP的cmd默認(rèn)沒有安裝ps,bash等命令,所以我們需要借助的三方的軟件來實(shí)現(xiàn)這個功能,這里使用cgywin,將cgywin的bin目錄加到環(huán)境變量的Path里面(下面使用Ant運(yùn)行cvs也會用到).
|
3.使用Ant運(yùn)行cvs
Ant內(nèi)置cvs屬性,可以很方便的使用cvs:
|
如果你的Documents and Settings中有.cvspass文件,那么可以不用設(shè)定cvsroot,Ant會自動尋找.
六.工程的打包部署
工程的打包,主要就是文件的操作,下面通過例子簡單介紹一下文件的移動,復(fù)制和刪除.
|
需要說明的是文件刪除的時候可能這個文件正在被別人是用而無法刪除,所以要用failonerror來標(biāo)記,文件的復(fù)制是時間戳敏感的,如果拷貝的文件比原文件要老,那么Ant將不會執(zhí)行copy,解決的辦法是將overwrite屬性設(shè)置為true,由于移動文件是復(fù)制文件的一個子類,所以它們的原理基本相同.
前面已經(jīng)例舉過一個jar文件打包的例子,下面主要介紹war文件的打包.Ant提供war文件打包的屬性.<war>任務(wù)是<jar>任務(wù)的子類,但是他也提供了一些特有的屬性:
|
可以看出war任務(wù)提供了許多WEB應(yīng)用程序的特有屬性,只要你指定了這些文件,war任務(wù)就會自動將他們放到正確的位置.
部署是項(xiàng)目發(fā)布的過程,Ant支持FTP,Email,本地和遠(yuǎn)程等幾種部署模式,但是Ant并不內(nèi)置對一些部署的支持,需要第三方的庫.
optional.jar 也可能是這樣的名字: jakarta-ant-1.4.1.optional.jar
netcomponents.jar <ftp>和<telnet>需要
activation.jar <mail>需要
mail.jar <mail>需要
下面只以本地部署為例,服務(wù)器為tomcat.
由于tomcat支持熱部署,可以將webapp文件下的war文件自解壓縮,所以最簡單的部署方式是將工程打成war包后直接copy到webapp目錄下面.另一種方法是使用tomcat的管理員身份,在manager頁面裝載和刪除應(yīng)用,這種方法比較復(fù)雜,也比較正規(guī),他也是遠(yuǎn)程部署的基礎(chǔ).
|
可以看出只要將上面的localhost換成目標(biāo)的ip地址就可以實(shí)現(xiàn)tomcat的遠(yuǎn)程部署.
ANT打包內(nèi)存溢出及JDK版本過低編繹失敗解決
,<javac classpathref=”project.class.path” debug=”true” deprecation=”true” destdir=”${dest}” nowarn=”false” target=”1.6″ >在此標(biāo)簽中增加fork=”true” memoryMaximumSize=”512m”就行了—也可以改更大
ANT編繹時出現(xiàn)以下錯誤:
please download the original output file to see more info—一般是因?yàn)镴DK版本過低,請?jiān)诃h(huán)境變量中設(shè)置高版本的JDK的JAVA_HOME及相應(yīng)的PATH變量.
總結(jié)
以上是生活随笔為你收集整理的Ant 下载、安装、使用、教程全面了解「建议收藏」的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【转】UIAutomation
- 下一篇: 在线客服系统源码(PHP完全开源版)