Ant 是一种构建java代码的工具,它用于构建一个软件产品,将编译,生成文档,单元测试,打包,部署,以及一些动态生成源代码集中在一起,由命令行(build.xml中)来集中解决,从而可以避免重复的劳动。它的优点主要有:
l 语法简单,只要你学过XML,就会看懂。
l 跨平台性,能比较灵活的处理java中的classpath和文件的目录结构(主要是使用datatype和特性,可以说两者是ant 的核心);
l 运行速度快,可直接在JVM中启动,因此可以缩短启动时间,同时Ant任务有一些检查的功能来避免额外的无用功;
l 它与JUnit测试框架紧密集成以实现极限编程的测试单元
l 内置对J2EE开发的支持
l 致力于解决JAVA的部署问题,例如FTP,Telnet,SQL命令等,所有这些都可以自动部署,有些还直接绑定到ant 中
l 有很多开源项目的标准,例如:Apache Tomcat 和 Apache Xerces
Ant 使用基于XML的构建文件来描述怎样构建,测试和部署应用程序。每个构建文件中都包含一个也只能是一个工程(对应标签是<project>),而一个工程中可以包含多个目标(对应标签是<target>)以实现构建过程,而各个目标之间可以相互依赖,这主要是通过<target>标签的depends属性。一个目标中可以包含多个任务,每个任务实际上是一个java类的引用,而这些类来至ant 内部或者扩展库,它们能理解构建文件中的参数,并且根据这些参数来执行任务。
一.完整的一个ant 工程构建过程
首先我们要检查一下ant 是否已经正确安装(具体过程这里不再重复了)。
1.编写一个简单的java程序
public class Main {
public static void main(String[] args){
for(int i=0;i<args.length;i++){
System.out.println(args[i]);
}
}
}
2.编写一个ant 构建文件
<?xml version=” 1.0” ?>
<project name=”firstbuild” default=”compile”>
<target name=”compile”>
<javac srcdir=”.”> //srcdir表示当前目录
<echo>compilation complete</echo> //echo用于返回屏幕的信息
</target>
</project>
3.运行第一个构建
打开命令窗口,进入存放java程序的目录下,在命令行键入 :ant
运行结果如下:
可以在ant命令后加上-verbose 参数,来获得更多的运行日志。
现在虽然能够用ant 编译文件,但构建过程很混乱,各种文件都在同一个文件夹下(例如 源文件,目标文件),工程在大一点,就会很混乱,难以控制。从而我们需要进行强制控制,以将源文件和生成的文件彻底分离放在不同的目录下;创建一个JAR文件用于包含编译后的代码。
Ant 工程将源文件,中间文件及发布包分隔在不同的目录下,从而易于管理,也更易于其他类似的文件整合:
目录 | 功能 |
src | 源文件 |
build/classes | 中间文件(生成的:可清理) |
dist | 可发布文件(生成的:可清理) |
那就来简单介绍一些比较常用的用于构建的标签。
<project>: build.xml文件中它是作为所有元素的最顶层元素存在,只允许出现次。它有三个比较常用的属性:
name: 指定工程的名字
default: 当没有指定运行的target时,运行的default指定的target
basedir: 用于计算其他路径的基路经,是生成一些目录和文件的
路径的依据
<mkdir> : 主要用于生成指定的路径结构的目录,例如 <mkdir dir=”build/classes”/> 就是在指定的根目录下生成有如dir值所示的目录结构的两个文件夹
<jar> : 最简单的作用是在目录树外用指定名称生成一个JAR文件: <jar destfile=”dist/project.jar” basedir=”build/classes”/>
这主要是将classes 文件夹下的所有classes文件打包生成一个名为project.jar的JAR文件,然后放在dist文件夹下
<javac> : 这个任务是执行编译java 文件的功能,例如:<javac srcdir=”src” destdir=”build/classes”/> 将src 文件夹下的所有文件编译,然后将生成的class文件放在classes文件夹下
<delete>:从它的名字我们就可以知道它的作用:将指定的文件或者文件集删除
例如:<delete dir="${build.base.dir}"/> 其中${build.base.dir}是一个特性引用,这个将在文章的后面部分介绍,在这里姑且将其认为代表了一个路径下的文件或者文件集
<copy>:同样我们也可以很容易知道它是一个实现了复制操作的标签,
<copy file="${web.xml}"
tofile="${build.classes.dir}/tmp/WEB-INF/web.xml" failοnerrοr="false"/>
通过file 确定所要拷贝的文件,当然是通过文件的地址来确定,而tofile 同理是拷贝的目的文件。
大多数情况下我们是用到以下的形式:
<copy todir="${build.classes.dir}/tmp/WEB-INF/classes">
<fileset dir="${build.classes.dir}/service">
<include name="**/*.class"/>
<include name="**/${handler.name}"/>
</fileset>
</copy>
在这个例子中我们用到了一个文件集(Fileset)的概念,所有的构建过程都要隐式地对一系列文件进行操作,例如编译,复制,删除还是以其他方式进行操作,ant 将文件集看作是本地的datatype。现在就举一些典型的例子。
<fileset dir=”lib”>
<include name=”*.jar”/>
</fileset>
包含所有lib目录下的JAR文件
<fileset dir=”web”>
<exclude name=”**/*.jsp”/>
</fileset>
包含WEB目录下所有非JSP页面文件
默认情况下,include和exclude 中的值是大小写敏感的,但可以通过设置casesensitive=”false”来取消它。<include>和<exclude>元素被称为模式集(patternset),ant 利用它来实现包含/排除的能力,模式集是与模式相匹配的文件的汇总,它只有被嵌入文件集,才能指向实际的文件。
模式匹配的功能有:
l * 指代从零到任意长的字符
l ?指代单一的字符
l ** 作为目录名,代表目录树上从当前节点往下的所有目录,可以是零到任意多个目录
l 以/或/结尾的模式意味着结尾是**。
模式集的属性(包含和排除模式使得文件集可以精确的定义只包含所需的文件)
属性 | 描述 |
include | 应包含的文件模式列表,以逗号分隔,省略时为包含所有文件 |
exclude | 应排除的文件模式列表,以逗号分隔,省略时为不排除任何文件(除了默认的排除文件) |
includesfile | 文件名称;该文件的每一行被看作是包含模式。 |
Excludesfile |
|
模式集可以被另一个模式集嵌套。
<condition> :主要用于测试一些条件,通过逻辑运算符<and><or>和<not>来提供特性设置的能力(以下均是<condition>的子元素)
元素 | 解释 |
<available> | 除了忽略特性和值之外,其他与<available>任务在语义和语法上相同,如果资源可用则设置为true |
<uptodate> | 除了忽略特性和值之外,其他与<uptodate>任务在语义和语法上相同,如果实最新的则设值为true |
<os> | 如果OS家族(mac,windows,dos,netware,os 2或unix) |
<equals> | 如果两个特性值相同则设值为true |
<isset> | 如果特性存在则设值为true |
<checksum> | 如果文件数量统计值相符合则设值为true |
<http> | 从URL中检查状态码小于500 |
<socket> | 检查特定主机和端口的socket监听器 |
<filename> | 对两个文件作逐字节的检查 |
<contains> | 测试一个字符串是否包含另一个,可选择是否大小写敏感 |
<istrue> | 如果值是on,true或yes则设值为true |
<isfalse> | <istrue>的否定 |
<condition>大体来讲是对运行环境的判断,为构建做好准备,它的取值是布尔型的
<java>:对于这个任务很容易理解,一看到他就知道他的功能是运行指定的程序。运行一个程序,我们首先需要设置他的classpath,当任何指定的classpath不存在时,<java>任务就使用ant 自身的classpath:例如ant.jar以及其他任何位于ANT_HOME/lib目录下的类库,再加上所有classpath环境变量中指定的内容(不能不指定,要不然运行时将出现错误)。添加classpath是很容易的:你只需在<classpath>元素中填写路径,或是提供classpath属性一个字符串形式的路径。
在<java>任务中,最重要的可选参数是嵌套参数列表。你要在任务<java>的<arg>元素中,通过一个值,一行文本,一个用于参数列表优先级解析的文件,或者一个路径来命名一个参数。<arg>元素有四个属性:
<arg>属性 | 含义 |
value | 字符串值 |
file | 文件或目录,在使用之前解析为绝对地址 |
line | 整个参数列表作为一个字符串传给任务 |
path | 一个字符串,包含有用冒号或分号隔开的文件或目录 |
<java>任务中有个failonerror 属性来处里错误,当这个属性的值设为on时,一旦发现错误,构建将中止。
<exec>:<exec>任务与<java>任务的功能相似,都是执行程序,不同之处在于<java>任务不具备访问地岑操作系统的能力,或者访问本地平台的构建步骤,而<exec>任务是专门用来运行本地程序的,具备了<java>任务所不具备的访问能力。
在GLASSFISH例子的build.xml文件中还出现了以下两条语句:
<!DOCTYPE project [
<!ENTITY testproperties SYSTEM "file:./build.properties">
]> 和 &testproperties;
这是 XML 支持的“以实体形式从其他文件载入片段的能力”,相当于 C/C++ 中的 include , 而 XML 中的插入是在声明和输入阶段进行。这里所谓的 ” 其他文件 ” ,是对 XML 文件中的所描述的数据进行限制、建模的文件,例如: DTD 文件, WSDL 文件,以及后面会提到的 properties 文件