簡介
Apache Ant是一個Java庫和命令行工具,其任務是將構建文件中描述的進程作為相互依賴的目標和擴展點。只要使用過Linux系統(tǒng)的讀者磅叛,應該知道 make這個命令屑咳。當編譯Linux內(nèi)核及一些軟件源程序時,經(jīng)常要用這個命令弊琴。Make命令其實就 是一個項目管理工具兆龙,而Ant所實現(xiàn)功能與此類似,像make访雪,gnumake和nmake這些編譯工具都有 一定的缺陷详瑞,但是Ant卻克服了這些工具的缺陷。
Ant的優(yōu)點
跨平臺性臣缀。Ant是存Java語言編寫的坝橡,所示具有很好的跨平臺性。
操作簡單精置。Ant是由一個內(nèi)置任務和可選任務組成的计寇。Ant運行時需要一個XML文件(構建文件)。
Ant通過調用target樹脂倦,就可以執(zhí)行各種task番宁。每個task實現(xiàn)了特定接口對象。由于Ant構建文件時XML格式的文件赖阻,所以和容易維護和書寫蝶押,而且結構很清晰。
Ant可以集成到開發(fā)環(huán)境中火欧。由于Ant的跨平臺性和操作簡單的特點棋电,它很容易集成到一些開發(fā)環(huán)境中去。
Ant的開發(fā)
Ant的構建文件
當開始一個新的項目時苇侵,首先應該編寫Ant構建文件赶盔。構建文件定義了構建過程,并被團隊開發(fā)中每個人使用榆浓。Ant構建文件默認命名為 build.xml于未,也可以取其他的名字。只不過在運行的時候把這個命名當作參數(shù)傳給Ant陡鹃。構建文件可以放在任何的位置烘浦。一般做法是放在項目頂層目錄中,這樣可以保持項目的簡潔和清晰杉适。下面是一個典型的項目層次結構谎倔。
( 注:很多項目的ant腳本中的命名基本上都是一致的,比如:編譯一般叫build或者compile猿推;打包一般叫jar或war片习;生成文檔一般命名為 javadoc或javadocs捌肴;執(zhí)行全部任務all。在每個任務的中藕咏,ANT會根據(jù)配置調用一些外部應用并配以相應參數(shù)執(zhí)行状知。雖然ANT可調用的外部應用種類非常豐富,但其實最常用的就2孽查,3個:比如javac javadoc jar等饥悴。)
(1) src存放文件。
(2) class存放編譯后的文件盲再。
(3) lib存放第三方JAR包西设。
(4) dist存放打包,發(fā)布以后的代碼答朋。
Ant構建文件是XML文件
每個構建文件定義一個唯一的項目(Project元素)贷揽。每個項目下可以定義很多目標(target元素),這些目標之間可以有依賴關系梦碗。當執(zhí)行這類目標時禽绪,需要執(zhí)行他們所依賴的目標。每個目標中可以定義多個任務洪规,目標中還定義了所要執(zhí)行的任務序列印屁。Ant在構建目標時必須調用所定義的任務。任務定義了Ant實際執(zhí)行的命令斩例。Ant中的任務可以為3類雄人。
(1) 核心任務。核心任務是Ant自帶的任務念赶。
(2) 可選任務柠衍。可選任務實來自第三方的任務晶乔,因此需要一個附加的JAR文件。
(3) 用戶自定義的任務牺勾。用戶自定義的任務實用戶自己開發(fā)的任務正罢。
Eclipse的集成ANT
打開Eclipse,點擊導航欄的"Window"-->"Preferences"-->"Ant"
創(chuàng)建一個java項目
在根目錄創(chuàng)建一個build.xml文件
切換默認的Ant版本驻民,Ant的插件管理
- 1翻具、菜單欄中打開Window-Preferences-Ant-Runtime
總共需要設置兩項:
1、Ant Home Entries(Default)回还,點擊Ant Home裆泳,選擇ant插件路徑:
2、設置Global Entries路徑柠硕,即為jdk中tools.jar路徑
Ant自動化構建
使用ant的主要工作就是配置它的xml文件工禾,默認為build.xml文件运提。
build.xml的配置參數(shù)
1.<project>標簽
每個構建文件都有一個對應<project>標簽,<project>標簽時構建文件的根標簽有以下屬性:
- default:表示默認的運行目標闻葵,即指定默認的target(即任務)民泵,這個屬性是必須的。
- basedir:表示項目的基準目錄槽畔。
- name:表示項目名栈妆。
- description:表示項目的描述。
每個項目對應一個構建文件厢钧,但是如果項目比較復雜鳞尔,包含大量的子項目,每一個子項目都對應有自己的構建文件早直。
2.<property>標簽
有兩個特點:
- 大小寫敏感
- 不可改變寥假,誰先設定,之后的都不能改變莽鸿。
語法:${property}
1 昧旨、設置 name 和 value 屬性值,比如: <property name="srcdir" value="${basedir}/src"/>
2 祥得、 設置 name 和 refid 屬性值兔沃,比如: <property name="srcpath" refid="dao.compile.classpath"/> ,其中dao.compile.classpath 在別的地方定義级及。
3 乒疏、設置 name 和 location 屬性值,比如: <property name="srcdir" location="src"/> 饮焦,即將 srcdir 的值設 置為:當前項目根目錄的 /src 目錄怕吴。
4 、設置 file 屬性值县踢,比如: <property file="build.properties"/> 转绷, 導入 build.properties 屬性文件中的屬性值
5 、設置 resource 屬性值硼啤,比如: <propety resource="build.properties"/>, 導入 build.properties 屬性文件中的屬性值
6 议经、設置 url 屬性值,比如: <property url="http://www.blogjava.net/wiflish/build.properties"/>, 導入http://www.blogjava.net/wiflish/build.properties 屬性文件中的屬性值谴返。
7 煞肾、設置環(huán)境變量,比如: <property environment="env"/> 嗓袱,設置系統(tǒng)的環(huán)境變量為前綴 env.
<property name="tomcat.home" value="${env.CATALINA_HOME}"/> 將系統(tǒng)的 tomcat 安裝目錄設置到 tomcat.home 屬性中籍救。
3.<import>標簽
引入別的xml文件,提高復用性
含有相同的 target渠抹,最終調用哪個target都是以 調用的那個xml文件為基礎蝙昙。若當前xml中沒有target闪萄,就會從import中尋找。
4.<target>標簽
任務耸黑,一個project標簽下有一個或多個target標簽桃煎,代表任務,任務間可以存在依賴關系大刊。有如下屬性:
- name表示目標名为迈,這個屬性是必須的。
- depends表示依賴的任務目標缺菌。
- if表示僅當屬性設置時才執(zhí)行葫辐,用于驗證指定的屬性是否存在,若不存在伴郁,所在target將不會被執(zhí)行耿战。
- unless表示當屬性沒有設置時才執(zhí)行。
- description表示項目的描述焊傅。
5.<echo>標簽
控制臺顯示剂陡,用于打印/輸出信息,類似于log4j的info方法
- <echo message="hello!"/>
- <echo message="${msg}"/>
- <echo>${msg}</echo>
- <echo>hello!</echo>
以上四種方式均可以顯示相應信息
6.<delete>標簽
該標簽用于刪除文件或文件目錄狐胎,有如下屬性:
- file:刪除文件
- dir:刪除目錄
- includeEmptyDirs:值得是否刪除空目錄鸭栖,默認是true
- failonerror:報錯是否停止,默認是true
- verbose:是否列出刪除的文件握巢,默認是false
<!--clean other dir-->
<target name="clean_other_dir">
<echo message="begin clean_other_dir..."/>
<delete dir="${basedir}/${compress.dir}"/>
<delete dir="${basedir}/pub"/>
<echo message="begin clean html module-xx..."/>
<delete includeemptydirs="true">
<fileset dir="${basedir}/src/html" >
<include name="**/module-*/**"/>
</fileset>
</delete>
<echo message="begin clean res/module-xx晕鹊、component-xx、res-base..."/>
<delete includeemptydirs="true">
<fileset dir="${basedir}/res" >
<include name="module-*/**"/>
<include name="component-*/**"/>
<include name="res-base/**"/>
</fileset>
</delete>
</target
7.<mkdir>標簽
該標簽用于創(chuàng)建一個目錄,它有一個屬性dir用來指定所創(chuàng)建的目錄名,其代碼如下:
- <mkdir dir=”${class.root}”/>
通過以上代碼就創(chuàng)建了一個目錄远豺,這個目錄已經(jīng)被前面的property標簽所指定。
8.<copy>標簽
該標簽用于拷貝文件或文件目錄飞几,屬性如下:
- file:表示源文件
- tofile:表示目標文件。
- todir:表示目標目錄独撇。
- overwrite:是否覆蓋目標文件循狰,默認為false
- includeEmptyDirs:是否拷貝空目錄,默認為true
- failonerror:如目標沒有發(fā)現(xiàn)是否自動停止券勺,默認值true
- verbose:是否顯示詳細信息,默認值false
<target name="cp">
<copy todir="${compress.dir}" overwrite="true">
<fileset dir="${ob_baseline.dir}">
<include name="pub/" />
<include name="res/" />
<include name="mail_template/" />
</fileset>
</copy>
</target>
9.<fileset>標簽
文件集標簽灿里,通常與任務結合來使用关炼,用于批量cope和delete
- dir:指定目錄
- include:包含的子目錄
10.<exec>執(zhí)行文件
用來執(zhí)行系統(tǒng)命令,或者指定環(huán)境的命令
打開命名行匣吊,并轉到c盤執(zhí)行dir命令
<target name="test">
<exec executable="cmd.exe">
<arg line="/c dir"/>
</exec>
</target>
能夠執(zhí)行系統(tǒng)命令儒拂,就相當于可以執(zhí)行各種環(huán)境比如node寸潦、gulp、bower等等:
<!--build style-->
<target name="build_style">
<echo message="begin build_style..."/>
<exec dir="." executable="gulp" failonerror="true">
<arg line="scss"/>
</exec>
</target>
<!--bower cache clean if必須是${]才是判斷true,false, 否則只要有設定值即可執(zhí)行-->
<target name="bower_cache_clean" if="${is_bower_cache_clean}">
<echo message="begin bower_cache_clean ..."/>
<exec dir="." executable="bower" failonerror="true">
<arg line="cache clean" />
</exec>
</target>
11.<jar>標簽
該標簽用來生成一個JAR文件社痛,其屬性如下
- destfile表示JAR文件名
- basedir表示被歸檔的文件名
- includes表示被歸檔的文件模式
- excludes表示被排除的文件模式
<war>標簽
該標簽用來生成一個WAR包,其屬性如下:
- destfile表示生產(chǎn)JAR文件名见转。
- dir表示被歸檔的文件目錄。
- includes表示別歸檔的文件模式蒜哀。
- exchudes表示被排除的文件模式斩箫。
12.<javac標簽>
該標簽用于編譯一個或一組java文件,其屬性如下
- srcdir表示源程序的目錄撵儿,必須的
- destdir表示class文件的輸出目錄乘客,默認是當前文件夾
- include表示被編譯的文件的模式
- excludes表示被排除的文件的模式
- classpath表示所使用的類路徑
- debug表示包含的調試信息
- optimize表示是否使用優(yōu)化
- verbose 表示提供詳細的輸出信息
- fileonerror表示當碰到錯誤就自動停止
13.<java>標簽
該標簽用來執(zhí)行編譯生成的.class文件其屬性如下
- classname 表示將執(zhí)行的類名
- jar表示包含該類的JAR文件名
- classpath所表示用到的類路徑
- fork表示在一個新的虛擬機中運行該類
- failonerror表示當出現(xiàn)錯誤時自動停止
- output 表示輸出文件
- append表示追加或者覆蓋默認文件
14.<antcall>標簽
AntCall 任務的作用是允許在一個target的執(zhí)行過程中調用并執(zhí)行其他的target,AntCall任務必須在target元素內(nèi)執(zhí)行淀歇,這個任務不能在target元素外執(zhí)行易核。
需要從一個target傳遞參數(shù)到被調用的target時,可以使用<param> 類型進行傳遞浪默,對于param 類型只有兩個屬性:name和value
<target name="sync_module_teach" if="${is_teach}">
<antcall target="sync_module_item">
<param name="html.dir" value="org"/>
</antcall>
</target>
執(zhí)行sync_module_item任務牡直,并設置參數(shù)html.dir的值為org。
該任務定義如下:
<target name="sync_module_item">
<echo message="begin sync_module ${html.dir}..."/>
<copy todir="${basedir}/src/html/${html.dir}" overwrite="true" includeEmptyDirs="true">
<fileset dir="${basedir}/lib">
<include name="module-*/**" />
</fileset>
</copy>
</target>
或者更為簡單的表達:
<target name="deploy">
<echo message="begin auto deploy......"/>
<antcall target="clean"/>
<antcall target="bower_install"/>
<antcall target="cnpm_install"/>
<antcall target="sync_module"/>
<antcall target="build_style"/>
<antcall target="nej_build" />
<antcall target="cp"/>
</target>
15.<parallel>標簽
并行執(zhí)行多個子任務
通過failonany控制如果一個失敗纳决,則不執(zhí)行碰逸。通過并行執(zhí)行,來提升性能岳链,降低構建花費的時間
<parallel failonany="true">
<antcall target="sync_module_corp"/>
<antcall target="sync_module_main"/>
<antcall target="sync_module_teach"/>
<antcall target="sync_module_backend"/>
<antcall target="sync_module_passport"/>
<antcall target="sync_module_business"/>
<antcall target="sync_module_k12_teach"/>
<antcall target="sync_module_k12_backend"/>
<antcall target="build_style"/>
</parallel>
**16.<regexp>標簽
用于正則的定義的使用花竞,可以與matches結合使用。
比如掸哑,定義正則:
<regexp id="regexp_env_test" pattern="^${root_dir}/(${test_dir}|${test_k12_dir})/.+"/>
<regexp id="regexp_env_pre" pattern="^${root_dir}/(${pre_dir}|${pre_k12_dir})/.+"/>
通過pattern指定正則內(nèi)容约急,通過id標識。
在需要匹配的時候苗分,使用之:
<condition property="is_test">
<matches string="${basedir}">
<regexp refid="regexp_env_test"/>
</matches>
</condition>
**17.<condition>標簽
用來判斷厌蔽,如果包含的內(nèi)容符合條件,則將property指定的屬性設置為true摔癣,否則為false奴饮。
比如上面的例子中,就是將basedir變量的值和regexp_env_test對應的正則匹配择浊,如果正確戴卜,就將is_test設置為true,然后后面的流程再去判斷琢岩。
與之配合的標簽有很多投剥,下面一一介紹:
- istrue,isfalse:斷言
<condition property="is_test_backend">
<and>
<istrue value="${is_test}"/>
<istrue value="${is_backend}"/>
</and>
</condition>
只有is_test和is_backend變量的值均為true,is_test_backend的值才為true担孔。
- and:邏輯與江锨,需要都滿足條件才行吃警,如上例所述。
- not:邏輯非啄育,反過來的結果酌心。
- or,xor:邏輯或和邏輯異或。
- isset:指定屬性是否存在:
<condition property="scondition">
<!--如果屬性name不存在則返回false-->
<isset property="name"/>
</condition>
- equils:指定屬性是否相等:
<condition property="scondition">
<!--如果arg1的值與arg2的值相等返回true挑豌,否則為false-->
<equals arg1="${name}" arg2="this is name"/>
</condition>
- filesmatch:指定文件是否相等:
<condition property="scondition">
<!--如果file1所代表的文件與file2所代表的文件相等返回true安券,否則為false-->
<filesmatch file1="testfile1.txt" file2="testfile2.txt"/>
</condition>
實例
<?xml version="1.0" encoding="utf-8"?>
<project name="project name" default="init" basedir=".">
<description>builds, tests, and runs the project. </description>
<!-- ********************************************************
引入資源和定義資源
******************************************************** -->
<!-- 引入資源 -->
<property file="build.properties"/>
<property environment="env"/>
<!--定義源程序文件夾-->
<property name="src.dir" location="src/java"/>
<property name="test.dir" location="test"/>
<property name="web.dir" location="web"/>
<!--定義目標程序文件夾-->
<property name="build.dir" location="build"/>
<property name="build.classes.dir" location="${build.dir}/classes"/>
<property name="build.test.dir" location="${build.dir}/test"/>
<property name="dist.dir" location="dist"/>
<!--定義其他文件夾-->
<property name="lib.dir" location="lib"/>
<property name="doc.dir" location="doc"/>
<property name="index.dir" location="index"/>
<property name="deploy.dir" location="${env.catalina_home}"/>
<property name="deploy.lib.dir" location="${deploy.dir}/lib"/>
<!--定義其他文件-->
<property name="dist.jar" location="${dist.dir}/web-inf/lib/${project.name}-${project.version}.jar"/>
<property name="deploy.war" location="${deploy.dir}/webapps/${project.name}.war"/>
<!--定義其他屬性-->
<available file="${dist.dir}/enduser.agreement" property="final.version"/>
<!-- ********************************************************
設置path
******************************************************** -->
<path id="project.classpath">
<pathelement location="${java.home}/jre/lib/rt.jar"/>
<pathelement location="${build.classes.dir}"/>
<pathelement location="${build.test.dir}"/>
<fileset dir="${deploy.lib.dir}">
<include name="**/*.jar"/>
</fileset>
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
</path>
<target name="init" description=" 信息 : 顯示項目基本信息.">
<tstamp>
<format property="now" pattern="yyyy-mm-dd hh:mm"/>
</tstamp>
<echo> ==================================================
顯示項目基本信息.
項目名稱: ${project.name}
項目版本: ${project.version}
作者 : ${author}
時戳 : ${dstamp}-${tstamp}
用法:
ant -buildfile build.xml compile 或
ant compile 或
ant 甚至
ant clean dist
幫助:
ant -projecthelp
==================================================</echo>
</target>
<target name="prepare" depends="init" description=" 準備 : 創(chuàng)建各種文件夾.">
<echo> ==================================================
創(chuàng)建各種文件夾.
================================================== </echo>
<!-- 創(chuàng)建源程序文件夾 -->
<mkdir dir="${src.dir}"/>
<mkdir dir="${test.dir}"/>
<mkdir dir="${web.dir}"/>
<mkdir dir="${web.dir}/web-inf"/>
<!-- 創(chuàng)建目標程序文件夾 -->
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.classes.dir}"/>
<mkdir dir="${build.test.dir}"/>
<mkdir dir="${dist.dir}"/>
<mkdir dir="${dist.dir}/web-inf"/>
<mkdir dir="${dist.dir}/web-inf/lib"/>
<!-- 創(chuàng)建其他文件夾 -->
<mkdir dir="${lib.dir}"/>
<mkdir dir="${doc.dir}"/>
<mkdir dir="${index.dir}"/>
</target>
<target name="javadoc" depends="prepare" description="生成文檔: 生成幫助文檔.">
<echo> ==================================================
生成幫助文檔.
==================================================</echo>
<javadoc packagenames="*.*" sourcepath="${src.dir}" destdir="${doc.dir}" author="true" version="true" use="true" encoding="utf-8">
<classpath refid="project.classpath"/>
</javadoc>
</target>
<target name="compile" depends="prepare" description=" 編譯 : 編譯所有源程序." unless="final.version">
<echo> ==================================================
編譯所有源程序.
==================================================</echo>
<javac srcdir="${src.dir}" destdir="${build.classes.dir}" debug="on" deprecation="on" encoding="utf-8">
<compilerarg value="-xlint:unchecked"/>
<classpath refid="project.classpath"/>
</javac>
<javac srcdir="${test.dir}" destdir="${build.test.dir}" encoding="utf-8">
<compilerarg value="-xlint:unchecked"/>
<classpath refid="project.classpath"/>
</javac>
</target>
<target name="test" depends="compile" description=" 測試 : 運行所有測試程序.">
<echo> ==================================================
運行所有測試程序.
==================================================</echo>
<junit haltonfailure="true">
<classpath refid="project.classpath"/>
<formatter type="brief" usefile="false"/>
<batchtest>
<fileset dir="${build.test.dir}" includes="**/*test.class"/>
</batchtest>
<sysproperty key="doc.dir" value="${doc.dir}"/>
<sysproperty key="index.dir" value="${index.dir}"/>
</junit>
</target>
<target name="dist" depends="compile" description=" 分發(fā) : 生成分發(fā)文件.">
<echo> ==================================================
生成分發(fā)文件:
${dist.jar}
==================================================</echo>
<!-- 從打包文件排除單元測試 -->
<jar destfile="${dist.jar}" basedir="${build.classes.dir}" includes="**/*.*" excludes="**/*test.class">
<!-- manifest="manifest.mf" > -->
<manifest>
<attribute name="author" value="${author}"/>
</manifest>
</jar>
</target>
<!-- ********************************************************
用于調試
******************************************************** -->
<target name="debug" depends="dist" description=" 調試 "/>
<!-- ********************************************************
用于效驗
******************************************************** -->
<target name="verify" depends="dist" description=" 效驗 "/>
<target name="run-deploy" depends="dist" description=" 部署 : 把文件部署到指定位置.">
<echo> ==================================================
把文件部署到指定位置:
${deploy.war}
==================================================</echo>
<copy todir="${dist.dir}/web-inf/lib">
<fileset dir="${lib.dir}" includes="*.jar"/>
</copy>
<copy todir="${dist.dir}">
<fileset dir="${web.dir}" includes="**/*.*"/>
</copy>
<jar destfile="${deploy.war}" basedir="${dist.dir}" includes="**/*.*" excludes="**/*test.class">
<!-- manifest="manifest.mf" > -->
</jar>
</target>
</project>
模板
以下xml依次定義了init(初始化),compile(編譯)浮毯,test(測試)完疫,doc(生成文檔),pack(打包)任務债蓝,可以作為模板
<?xml version="1.0" encoding="utf-8"?>
<project name="Hello world" default="doc">
<!-- properies -->
<property name="src.dir" value="src" />
<property name="report.dir" value="report" />
<property name="classes.dir" value="classes" />
<property name="lib.dir" value="lib" />
<property name="dist.dir" value="dist" />
<property name="doc.dir" value="doc"/>
<!-- 定義classpath -->
<path id="master-classpath">
<fileset file="${lib.dir}/*.jar" />
<pathelement path="${classes.dir}"/>
</path>
<!-- 初始化任務 -->
<target name="init">
</target>
<!-- 編譯 -->
<target name="compile" depends="init" description="compile the source files">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}" target="1.4">
<classpath refid="master-classpath"/>
</javac>
</target>
<!-- 測試 -->
<target name="test" depends="compile" description="run junit test">
<mkdir dir="${report.dir}"/>
<junit printsummary="on"
haltonfailure="false"
failureproperty="tests.failed"
showoutput="true">
<classpath refid="master-classpath" />
<formatter type="plain"/>
<batchtest todir="${report.dir}">
<fileset dir="${classes.dir}">
<include name="**/*Test.*"/>
</fileset>
</batchtest>
</junit>
<fail if="tests.failed">
***********************************************************
**** One or more tests failed! Check the output ... ****
***********************************************************
</fail>
</target>
<!-- 打包成jar -->
<target name="pack" depends="test" description="make .jar file">
<mkdir dir="${dist.dir}" />
<jar destfile="${dist.dir}/hello.jar" basedir="${classes.dir}">
<exclude name="**/*Test.*" />
<exclude name="**/Test*.*" />
</jar>
</target>
<!-- 輸出api文檔 -->
<target name="doc" depends="pack" description="create api doc">
<mkdir dir="${doc.dir}" />
<javadoc destdir="${doc.dir}"
author="true"
version="true"
use="true"
windowtitle="Test API">
<packageset dir="${src.dir}" defaultexcludes="yes">
<include name="example/**" />
</packageset>
<doctitle><![CDATA[<h1>Hello, test</h1>]]></doctitle>
<bottom><![CDATA[<i>All Rights Reserved.</i>]]></bottom>
<tag name="todo" scope="all" description="To do:" />
</javadoc>
</target>
</project>