Ant是一个用于简单或复杂Java工程的自动化构建、部署工具,它对于那些具有分布式开发团队或者相信通过频繁的构建来进行不间断集成的公司尤其有用。对于那些建立传统全Java应用程序以及那些使用HTML、JSP和Java servlets创建Web应用程序的公司来说,Ant极具价值。无论你的Java开发者使用什么操作系统、集成开发环境或者构建环境,Ant都可以将你的工程集合在一起,用于那些重要的构建。Ant也能够自动化并且同步文档部署,这通常发生在软件开发过程中的没有正式文档和文档比较混乱的部分。
在构建和部署Java应用程序的时候,Ant处理着大量有用的任务。最基本的任务包括添加和移除目录、使用FTP拷贝和下载文件、创建JAR和ZIP文件以及创建文档。更高级的特性包括用源代码控制系统诸如CVS或者SourceSafe来检查源代码、执行SQL查询或脚本、将XML文件转换为人能识别的HTML,以及为远程方法调用生成stub(存根)文件。
Ant和Make(非常著名的构建工具,很多C语言开发人员都使用它)之间有什么不同?Ant是为Java而创建,带有属于其自身的、独特的范例,具有可移植性。而Make依赖于固定的操作系统命令(因此一个运行在微软Windows下的Make文件对于使用UNIX的开发者来说毫无用处),利用Ant构建的纯Java工程是可移植的,因为Ant本身就是用Java编写的,并且Ant bulidfiles使用XML语法。
1.下载及安装
Apache Ant是一个基于Java的构建工具,满足跨平台使用。
下载及安装:
解压下载的Ant拷贝到任意目录以D:\Program Files\apache-ant-1.8.4为例
将D:\Program Files\apache-ant-1.8.4配置为系统变量ANT_HOME
在PATH中加入%ANT_HOME%\bin
命令提示符中输入ant相关命令可以查看是否配置正确。
2.简单实例
实例:编译运行一个简单的类。
编写一个简单的HelloWorld
public class HelloWorld{ public static void main(String[] args){ System.out.println("Hello, ANT!!!"); } }
建立build.xml(名称可改)
HelloWorld.java和build.xml所在目录示意:
├src
│ └HelloWorld.java
└build.xml
<?xml version="1.0" encoding="UTF-8"?> <project name="antStudyProj" default="run" basedir="."> <property name="classdir" value="build/classes"/> <echo message="Learn Ant!!!"/> <target name="clean"> <delete dir="${classdir}"/> </target> <target name="compile" depends="clean"> <mkdir dir="${classdir}" /> <javac srcdir="src" destdir="${classdir}" includeantruntime="false"/> </target> <target name="run" depends="compile"> <java classname="HelloWorld"> <classpath path="${classdir}"/> </java> </target> </project>
运行Ant,查看结果(可以通过ant -help查看ant命令的使用)
这里使用ant -buildfile build.xml文件的绝对路径来运行,结果如下:
注意:可以通过其他方式也可运行ant,ant的入口为org.apache.tools.ant.launch.Launcher,里面包含mian方法,可指定执行该类并传入参数。
3.buildfile介绍
这是官网的build.xml示例
<project name="MyProject" default="dist" basedir="."> <description> simple example build file </description> <!-- set global properties for this build --> <property name="src" location="src"/> <property name="build" location="build"/> <property name="dist" location="dist"/> <target name="init"> <!-- Create the time stamp --> <tstamp/> <!-- Create the build directory structure used by compile --> <mkdir dir="${build}"/> </target> <target name="compile" depends="init" description="compile the source " > <!-- Compile the java code from ${src} into ${build} --> <javac srcdir="${src}" destdir="${build}"/> </target> <target name="dist" depends="compile" description="generate the distribution" > <!-- Create the distribution directory --> <mkdir dir="${dist}/lib"/> <!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file --> <jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/> </target> <target name="clean" description="clean up" > <!-- Delete the ${build} and ${dist} directory trees --> <delete dir="${build}"/> <delete dir="${dist}"/> </target> </project>
buildfile使用XML编写。每个buildfile包含一个project元素,而project元素至少有一个target。
project有三个属性name、default、basedir,都不是必须的。
name:项目名称
default:指定默认执行的target
basedir:故名思意就是工作的根目录 .代表当前目录
project中可以定义多个target。Target是要执行的tasks的集合。
target有以下属性:name,depends,if,unless,description,extensionOf,onMissingExtensionPoint。
name:target的名字,必须
depends:此target依赖的targets,用逗号隔开,非必须
if:某个属性存在或表达式的计算结果为true,非必须
unless:和if对应,非必须
description:对target的描述,非必须
task能被执行的一段代码,结构如下
<name attribute1="value1" attribute2="value2" ... />
Property属性可以通过name及value定义属性,或通过file指定载入的属性文件等。
当定义了一个name为example的属性后,可通过${example}进行引用。
<property name="foo.dist" value="dist"/>
将属性foo.dist的值设置为dist
<property file="foo.properties"/>
从foo.properties文件中读取属性
<property url="http://www.mysite.com/bla/props/foo.properties"/>
从url指定的properties中读取所有属性
Classpath有两个属性path和location,path指定jar包,location指定包含jar包的路径。可以通过fileset和dirset简化配置。
<classpath> <pathelement path="${classpath}"/> <fileset dir="lib"> <include name="**/*.jar"/> </fileset> <pathelement location="classes"/> <dirset dir="${build.dir}"> <include name="apps/**/classes"/> <exclude name="apps/**/*Test*"/> </dirset> <filelist refid="third-party_jars"/> </classpath>
4.Ant流程控制 if elseif else
使用循环,判断等控制时需添加ant-contrib包。
taskdef定义第三方的任务,主要包含ant的处理流程逻辑
if elseif else格式如下
<property name="hello" value="false"/> <taskdef resource="net/sf/antcontrib/antcontrib.properties" classpath="D:\Program Files\apache-ant-1.8.4\lib\ant-contrib-1.0b3.jar" /> <target name="run" depends="compile"> <java classname="HelloWorld"> <classpath path="${classdir}"/> </java> <if> <equals arg1="${hello}" arg2="true"/> <then> <echo>${hello} is true</echo> </then> <elseif> <equals arg1="${hello}" arg2="false"/> <then> <echo>${hello} is false</echo> </then> </elseif> <else> <echo>${hello}</echo> </else> </if> </target>
5.常用task
使用classpath
<target> <javac> <classpath refid="project.class.path"/> </javac> </target>
设置classpath
<classpath id="project.class.path"> <pathelement path="${classpath}"/> <fileset dir="lib"> <include name="**/*.jar"/> </fileset> <pathelement location="classes"/> <dirset dir="build"> <include name="apps/**/classes"/> <exclude name="apps/**/*Test*"/> </dirset> <filelist refid="third-party_jars"/> </classpath>
输出信息
<echo message="XXX"/> <echo>XXX</echo>
引入一个XML文件
<import file="../common-targets.xml"/>
拷贝文件
<copy file="myfile.txt" tofile="mycopy.txt"/> <copy file="myfile.txt" todir="../otherdir"/> <copy todir="..//newdir"> <fileset dir="src_dir"/> </copy> <copy todir="../destdir"> <fileset dir="src_dir"> <exclude name="**/*.java"/> </fileset> </copy> <copy todir="../destdir"> <fileset dir="src_dir" excludes="**/*.java"/> </copy> <!--拷贝一个文件集合到一个目录,同时建立备份文件--> <copy todir="../backup/dir"> <fileset dir="src_dir"/> <globmapper from="*" to="*bak"/> </copy> <!--拷贝一个集合的文件到指定目录,并替换掉TITLE--> <copy todir="../backup/dir"> <fileset dir="src_dir"/> <filterset> <filter token="TITLE" value="Foo Bar"/> </filterset> </copy> <copydir src="${src}/resources" dest="${dest}" includes="**/*.java" excludes="**/Test.java"/> <copyfile src="test.java" dest="subdir/test.java"/>
删除文件、目录
<delete file="/lib/ant.jar"/> <delete dir="/lib"/> <delete> <fileset dir="." includes="**/*.bak"/> </delete> <!--删除当前目录下所有的文件和目录,包括当前目录--> <delete includeEmptyDirs="true"> <fileset dir="build"/> </delete> <!--删除当前目录下所有的文件和目录,不包括当前目录--> <delete includeEmptyDirs="true"> <fileset dir="build" includes="**/*"/> </delete> <!--删除当前目录下所有的svn相关文件(因为SVN文件默认是excludes的,所以这里说明一下)--> <delete defaultExcludes="false"> <fileset dir="${src}" includes="**/*.svn"/> </delete> <!--删除文件目录树--> <deltree dir="dist"/>
剪切文件
<move todir="some/new/dir"> <fileset dir="my/src/dir"> <include name="**/*.jar"/> <exclude name="**/ant.jar"/> </fileset> </move>
重命名
<rename src="foo.jar" dest="ant-${version}.jar"/>
建立临时文件
<!--在目录build下,建立文件名为temp.file,后缀名为xml的文件--> <tempfile property="temp.file" destDir="build" suffix=".xml"/>
Touch使用
<!--如果文件不存在,创建文件,如果存在,更改最后访问时间为当前系统时间--> <touch file="myfile"/> <!--如果文件不存在,创建文件,更改最后访问时间--> <touch file="myfile" datetime="06/28/2000 2:02 pm"/> <!--更改目录下所有文件的最后访问时间--> <touch datetime="09/10/1974 4:30 pm"> <fileset dir="src_dir"/> </touch>
Condition的使用 <and> <or> <not>等tag
peoperty: The name of the property to set
value: The value to set the property to.
else: The value to set the property to if the codition evaluates to false.
<condition property="isMacOsButNotMacOsX"> <and> <os family="mac"> <not> <os family="unix"> </not> </and> </condition>
替换
<replace file="configure.sh" value="defaultvalue" propertyFile="src/name.properties"> <replacefilter token="@token1@"/> <replacefilter token="@token2@" value="value2"/> <replacefilter token="@token3@" property="property.key"/> <replacefilter> <replacetoken>@token4@</replacetoken> <replacevalue>value4</replacevalue> </replacefilter> </replace>
调用chmod
<chmod perm="go-rwx" type="file"> <fileset dir="/web"> <include name="**/*.cgi"/> <include name="**/*.old"/> </fileset> <dirset dir="/web"> <include name="**/private_*"/> </dirset> </chmod>
设置property
<!--设置属性name-value--> <property name="foo.dist" value="dist"/> <!--读取属性文件中的属性配置--> <property file="foo.properties"/> <!--读取网络中的property-set--> <property url="http://www.mysite/props/foo.properties"/> <!--读取文件中的属性配置--> <property resource="foo.properties"/> <!--读取环境变量--> <property environment="env"/>
显示错误信息
Fail task 退出当前构建,抛出BuildException,打印错误信息。
message:A message giving further information on why the build exited
if:Only fail if a property of the given name exists in the current project
unless:Only fail if a property of the given name doesn't exist in the current project
status:Exit using the specified status code; assuming the generated Exception is not caught, the JVM will exit with this status.Since Apache Ant 1.6.2
<fail>Something wrong here.</fail> <fail message="${属性}"/> <!--如果这个属性不存在,显示错误--> <fail unless="failCondition" message="unless Condition"/> <!--如果这个属性存在,显示错误--> <fail if="failCondition" message="if Condition"/> <!--如果符合条件,显示错误--> <fial message="tag condition"> <condition> <not> <isset property="failCondition"/> </not> </condition> </fail>
创建目录
<mkdir dir="${dist}/lib"/>
打jar包
<jar destfile="${dist}/lib/app.jar" basedir="${build}/classes"/> <jar destfile="${build}/lib/app.jar" basedir="${build}/classes" includes="mypackage/test/**" excludes="**/Test.class"/>
打ear包
<ear destfile="build/myapp.ear" appxml="src/metadata/application.xml"> <fileset dir="build" includes="*.jar,*war"/> </ear>
执行程序
<target name="help"> <exec executable="cmd"> <arg value="/c"> <arg value="ant.bat"/> <arg value="-p"/> </exec> </target>
运行jar包
<java classname="test.Main" dir="${exec.dir}" jar="${exec.dir}/dist/test.jar" fork="true" failonerror="true" maxmemory="128m"> <arg value="-h"/> <classpath> <pathelement location="dist/test.jar"/> <pathelement path="/Users/antoine/dev/asf/ant-core/bootstrap/lib/ant-launcher.jar"/> </classpath> </java>
编译程序
<javac srcdir="${src}" destdit="${build}" classpath="xyz.jar" debug="on" source="1.4"/>
Length使用
<!--把字符串foo的长度保存到属性length.foo中--> <length string="foo" property="length.foo"/> <!--把文件bar的长度保存到属性length.bar--> <length file="bar" property="length.bar"/>
输入input
输入值保存在db.user中
<input message="Please enter db-username:" addproperty="db.user" defaultvalue="Scott-Tiger"/>
压缩、解压缩
<!--解压缩zip文件--> <unzip src="apache-ant-bin.zip" dest="${tools.home}"> <patternset> <include name="apache-ant/lib/ant.jar"/> </patternset> <mapper type="flatten"/> </unzip> <!--压缩zip文件--> <zip destfile="${dist}/manual.zip" basedir="htdoc/manual" includes="api/**/*.html" excludes="**/todo.html"/> <!--打tar包--> <tar destfile="/Users/antoine/dev/asf/ant-core/docs.tar"> <tarfileset dir="${dir.src}/doc" fullpath="/usr/doc/ant/README" preserveLeadingSlashes="true"> <include name="readme.txt"/> <tarfileset> <tarfileset dir="${dir.src}/docs" prefix="/usr/doc/ant" preserveLeadingSlashes="true"> <include name="*.html"/> </tarfileset> </tar> <!--解压tar包--> <untar src="tools.tar" dest="${tools.home}"/>
打war包
<war destfile="myapp.war" webxml="src/metadata/myapp.xml"> <fileset dir="src/html/myapp"/> <fileset dir="src/jsp/myapp"/> <lib dir="thirdparty/libs"> <exclude name="jdbc1.jar"> </lib> <classes dir="build/main"/> <zipfileset dir="src/graphics/images/gifs" prefix="images"/> </war>