1 前言
Ant是一种基于Java的生成工具。从作用上看,它有些类似于C编程(UNIX平台上使用较多)中的Make工具,C/C++项目经常使用Make工具来管理整个项目的编译、生成。
Make使用Shell命令来定义生成任务,并定义任务之间的依赖关系,以便它们总是以必须的顺序来执行。
Make工具主要有如下两个缺陷。
- Make工具的本质还是依赖UNIX平台的Shell语言,所以Make工具无法跨平台
- Make工具的生成文件的格式比较严格,容易导致错误
Ant工具是基于Java语言的生成工具,所以具有跨平台的能力:而且Ant工具使用XML文件来编写生成文件,因而具有更好的适应性。
由此可见,Ant是Java世界的Make工具,而且这个工具是跨平台的,并具有简单、易用的特性。
由于Ant具有跨平台的特性,所以编写Ant生成文件时可能会失去一些灵活性。为了弥补这个不足,Ant提供了一个“exec”核心任务,这个任务允许执行特定操作系统上的命令。
2 Ant的下载和安装
下载和安装Ant按如下步骤进行。
Step 1:登录http://ant.apache.org/bindownload.cgi
站点下载Ant最新版。虽然Ant是基于Java的生成工具,具有平台无关的特性,但考虑到解压缩的方便性,通常建议Windows平台下载*.zip压缩包,而Linux平台则下载.gz压缩包。
Step 2:将下载的压缩文件解压缩到任意路径,并将Ant文件夹重命名为Ant194.解压缩后看到如下文件结构:
- bin:启动和运行Ant的可执行命令
- etc:包含一些样式单文件,通常无需理会该目录下的文件
- lib:包含Ant的核心类库,以及编译和运行Ant所依赖的第三方类库
- manual:Ant工具的相关文档,这些文档对学习使用Ant有很大作用
- LICENSE等说明性文档
提示:重命名Ant文件夹仅仅是为了方便、简捷,并不是必需的。
Step 3:Ant的运行需要如下两个环境变量。
- JAVA_HOME:该环境变量指向JDK安装路径。如果已经成功安装了Tomcat,则该环境变量应该已经是正确的。
- ANT_HOME:该环境变量应指向Ant安装路径
按前面介绍的方式配置ANT_HOME环境变量。
提示:Ant安装路径就是前面释放Ant压缩文件的路径,Ant安装路径下应该包含bin、etc、lib和manual这4个文件夹
Step 4:Ant工具的关键命令就是%ANT_HOME%/bin
路径下的ant.bat
命令,如果希望操作系统可以识别该命令,还应该将%ANT_HOME%/bin路径添加到操作系统的PATH环境变量中。
提示:当在命令行窗口、Shell窗口输入一条命令后,操作系统会到PATH环境变量所指定的系列路径中去搜索,如果找到了该命令所对应的可执行程序,即运行该命令,否则将提示找不到命令。如果不嫌麻烦,愿意每次都输入%ANT_HOME%/bin/ant.bat
的全路径来运行Ant工具,则无须将%ANT_HOME%/bin路径添加到PATH环境变量之中。
经过上面4个步骤,Ant安装成功,启动命令行窗口,输入ant.bat
命令,则应该可以看到如下提示:
1 | Buildfile: build.xml does not exist! |
3 使用Ant工具
使用Ant非常简单,当正确的安装Ant后, 只要输入ant或ant.bat即可。
如果运行ant命令时没有指定任何参数,Ant会在当前目录下搜索build.xml文件。如果找到了就以该文件作为生成文件,并执行默认的target。
如果运行时使用-find或者-s选项(这两个选项的作用完全相同),Ant就会到上级目录中搜索生成文件,直至到达文件系统的根路径。
要想让Ant使用其他生成文件,可以用-buildfile<生成文件>
选项,其中-buildfile
可以使用-file
或-f
来代替,这三个选项的作用完全一样。例如如下命令:
1 | ant -f a.xml // 显示指定使用a.xml作为生成文件 |
如果希望Ant运行时只输出少量的必要信息, 则可使用-quiet或-q选项:如果希望Ant运行时输出更多的提示信息,则可使用-verbose或-v选项
如果希望Ant运行时将提示信息输出到指定文件,而不是直接输出到控制台,则可使用-logfile<file>
或-l<file>
选项。例如如下命令:
1 | ant -verbose -l a.log // 运行Ant时生成更多的提示信息,并将提示信息输出到a.log文件中 |
除此之外,Ant还允许运行时指定一些属性来覆盖生成文件中指定的属性值(使用Property task来指定),例如使用-D<property>=<value>
,则此处指定的value将会覆盖生成文件中property的属性值。例如如下命令:
1 | ant -Dbook=Spring4 // 该命令将会覆盖生成文件中的book属性值 |
通过该方法可以将操作系统的环境值传入生成文件,例如在运行Ant工具时使用如下命令:
1 | ant -Denvl=%ANT_HOME% |
上面命令中的代码用于向生成文件中传入一个envl属性,而该属性的值并没有直接给出,而是用%ANT_HOME%的形式给出——这是Windows下访问环境变量的方式。通过这种方式,就可以将Windows环境变量值传入生成文件了,如果希望在生成文件中访问到该环境变量的值,使用$envl即可。
上面命令在Linux平台上改为:ant-Denvl=$ANT_HOME
,Linux下以$符来访问环境变量。
在默认情况下,Ant将运行生成文件里指定的默认target,如果运行ant时显示指定希望运行的target,则可采用如下命令格式:
1 | ant [target1 [target2 [target3] ...]] |
实际上,如果读者需要获取ant命令的更多详细情况,直接使用ant -help
选项即可。运行ant -help
,将看到如图所示的提示信息。
4 定义生成文件
实际上,使用Ant的关键就是编写生成文件,生成文件定义了该项目的各个生成任务(以target来表示,每个target表示一个生成任务),并定义生成任务之间的依赖关系。
Ant生成文件的默认名为build.xml
,也可以取其他名字。但如果为该生成文件起其他名字,将意味着要将这个文件名作为参数穿个Ant工具。生成文件可以放在项目的任意位置,但通常做法是放在项目的顶层目录,这样有利于保持项目的简洁和清晰。
下面是一个典型的项目层次结构。
1 | <project>:该文件存放了整个项目的全部资源 |
Ant生成文件的根目录是<project.../>
,每个项目下可以定义多个生成文件,每个生成目标以一个<target.../>
元素来定义,它是<project.../>
元素的子元素。
project元素可以有多个属性,project元素的常见属性的含义如下:
- default:指定默认target,这个属性是必需的。如果运行
ant.bat
命令时没有显示指定想执行的target,Ant将执行该target - basedir:指定项目的基础路径,生成文件中的其他相对路径都是基于该路径的
- name:指定项目文件名,该属性仅指定一个名字,对编译、生成项目没有太大的实际作用
- description:指定项目的描述信息,对编译、生成项目没有太大的实际作用
例如,如下代码片段:
1 |
|
每个生成目标对应一个<target…/>元素。
- name:指定该target的名称,该属性是必需的。该属性非常重要,当希望Ant运行指定的生成目标时,就是根据该name来确定生成目标的。因此可以得出一个结论:同一个生成文件里不能有两个同名的target元素。
- depends:该属性可指定一个或多个target名,表示运行该target之前应运行该depends属性所指定的一个或多个target。
- if:该属性指定一个属性名,用属性表示仅当设置了该属性时才执行此target
- unless:该属性指定一个属性名,用属性表示仅当没有设置该属性时才执行此target
- description:指定该target的描述信息
例如,如下配置片段:
1 | <!-- 下面表示执行run target之前,必需先执行compile target --> |
每个生成目标又可能由一个或多个任务序列组成,当执行某个生成目标时,实际上就是依次完成该目标所包含的全部任务,每个人物有一段可执行的代码组成。
定义任务的代码格式如下:
1 | <name attribute1="value1" attribute2="value2" .../> |
上面代码中的name是任务的名称,attributeN和valueN用于指定执行该任务所需的属性名和属性值。
简而言之,Ant生成文件的基础结构是project元素里包含多个target元素,而每个target元素里包含多个任务。由此可见,Ant生成文件具有如图所示的结构。
Ant的任务可以分为如下三类。
- 核心任务:核心任务是Ant自带的任务
- 可选任务:可选任务是来自第三方的任务,因此需要一个附加的JAR文件
- 用户自定义的任务:用户自定义的任务是用户自己开发的任务
除此之外,<project.../>
元素还可拥有如下两个重要的子元素。
- <property…/>:用于定义一个或多个属性
- <path…/>:用于定义一个或多个文件和路径
4.1 property元素
<property…/>元素用于定义一个或多个属性,Ant生成文件中的属性类似于编程语言中的宏变量,他们都具有名称和值。与编程语言不同的是,Ant生成文件中的属性值不可改变
定义一个属性的最简单形式如下:
1 | <!-- 下面代码定义了一个名为builddir的属性,其值为dd --> |
如果需要获取属性值,则使用${propName}
的形式。例如,如下代码即可获取builddir属性值:
1 | // 输出builddir属性值 |
由此可见,$符在Ant生成文件中具有特殊意义,如果希望Ant将生成文件中的$当成普通字符,则应用使用$$。例如,如下配置片段:
1 | <echo>$${builddir}=${builddir}<echo> |
上面代码中的$${builddir}不会获取builddir属性值,而${builddir}才会获取builddir属性值。执行上面任务将会输出:
1 | [echo] ${builddir}=dd |
提示:echo是Ant的核心任务之一,该任务直接输出某个字符串,通常用于输出某些提示信息。
实际上,<property…/>元素可以接受如下几个常用属性。
- name:指定需要设置的属性名
- value:指定需要设置的属性值
- resource:指定属性文件的资源名称,Ant将负责从属性文件中读取属性名和属性值
- file:指定属性文件的文件名,Ant将负责从属性文件中读取属性名和属性值
- url:指定属性文件的URL地址,Ant将负责从属性文件中读取属性名和属性值
- environment:用于指定系统环境变量的前缀。通过这种方式允许Ant访问系统环境变量
- classpath:指定搜索属性文件的classpath
- classpathref:指定搜索属性文件的classpath引用,该属性并不是直接给出classpath值,而是引用<path…/>元素定义的文件或路径集
下面给出几个使用property元素的例子。
1 | <!-- 指定读取foo.properties属性文件中的属性名和属性值 --> |
property元素所读取的属性文件就是普通的属性文件,该文件的内容由一系列的name=value组成,如下面的配置片断所示。
1 | author=Oh_MyBug |
除此之外,通过property元素之后,就可以在Ant生成文件中通过如下方式来访问操作系统环境变量:
1 | <!-- 输出JAVA_HOME环境变量 --> |
即可看到本机器上JAVA_HOME环境变量的值
4.2 path元素和classpath元素
使用Ant编译、运行java文件时常常需要引用第三方JAR包,这就需要使用<classpath…/>元素了。<path…/>元素和<classpath…/>元素都用于定义文件和路径集,区别是classpath元素通常作为其他任务的子元素,既可引用已有的文件和路径集,也可临时定义一个文件和路径集;而<path../>元素则作为<project…/>元素的子元素,用于定义一个独立的、有名称的文件和路径集,用于被引用。
因为<path…/>和<classpath…/>元素都用于定义文件和路径集,所以也将<path…/>和<classpath…/>元素定义的内容称为Path-like Structures
(似目录结构)
<path…/>和<classpath…/>元素都用于收集系列的文件和路径集,这两个元素都可接收如下子元素。
- <pathelement…/>:用于指定一个或多个目录
- <dirset…/>:采用模式字符串的方式指定系列目录
- <fileset…/>:采用模式字符串的方式指定系列文件
- <pathelement…/>:用于指定一个或多个目录。pathelement元素可以指定如下两个属性中的一个
- <path…/>:指定一个或者多个目录(或者JAR文件),多个目录或JAR文件之间以英文冒号(:)或英文分号(;)分开
- <location…/>:指定一个目录和JAR文件。
提示:因为JAR文件还可以包含更多层次的文件结构,所以JAR文件实际上可以看成是一个文件路径
例如,如下配置片段:
1 | <!-- 定义/path/to/file2.jar、/path.to.class2和/path.to.class3所组成的路径集 --> |
如果需要指定多个路径集,则应该使用<dirset.../>
元素,该元素需要一个dir属性,dir属性指定该路径集的根路径。除此之外,dirset还可以使用<include.../>
和<exclude.../>
两个子元素来指定包含和不包含哪些目录,例如下面的配置片段:
1 | <!-- 指定该路径集的根路径是build目录 --> |
上面的配置文件代表build/apps目录下,所有名为classes且文件名不包含Test子串的目录。
如果希望配置多个文件,则可用<fileset.../>
或者<filelist.../>
元素,通常<fileset…/>元素使用模式字符串来匹配文件集,而<filelist…/>则通过列出文件名的方式来指定文件集。
<filelist…/>元素需要指定如下两个属性。
- dir:指定文件集里多个文件所在的基准路径。这是一个必需的属性。
- files:多个文件名列表,多个文件名之间以英文逗号(,)或空白隔开。
例如,下面的示例配置片段:
1 | <!-- 配置src/foo.xml和src/bar.xml文件组成的文件集 --> |
提示:几乎所有的Ant元素都可以指定两个属性:id和refid,其中id用于为该元素指定一个唯一标识,而refid用于指定引用另一个元素,例如下面的filelist配置:
1 | <filelist refid="docfiles"/> |
该filelist元素包含的文件集和前面docfiles文件集里包含的文件完全一样。
实际上,<filelist…/>还允许使用多个<file…/>子元素来指定文件列表,例如下面的配置片段:
1 | <filelist id="docfiles" dir="${doc.src}"> |
<fileset…/>元素可指定如下两个属性:
- dir:指定文件集里多个文件所在的基准路径。这里一个必需的属性
- casesensitive:指定是否区分大小写。默认区分大小写。
除此之外,<fileset…/>元素还可以使用<include…/>和<exclude…/>两个子元素来指定包含和不包含哪些文件,例如下面的配置片段:
1 | <!-- 定义src路径下的文件集 --> |
掌握了<pathelement…/>、<dieset…/>、<filelist…/>和<fileset…/>4个元素的用法之后,就可以使用<path…/>或者<classpath…/>将它们组合在一起使用了,例如下面的配置片段:
1 | <path id="classpath"> |
5 Ant的任务(task)
Ant提供了大量的核心task和可选task,除此之外,Ant还允许用户定义自己的task,这大大扩展Ant的功能。
下面简要介绍一些常用的核心task:
- javac:用于编译一个或多个Java源文件,通常需要srcdir和destdir两个属性,用于指定Java源文件的位置和编译后class文件的保存位置。
- java:用于运行某个Java类,通常需要classname属性,用于指定需要运行哪个类。
- jar:用于生成JAR包,通常需要指定destfile属性,用于指定所创建JAR包的文件名。除此之外,通常还应指定一个文件集,表明需要建那些文件打包到JAR包里。
- sql:用于执行一条或多条SQL语句,通常需要driver、url、userid和password等属性,用于指定连接数据库的驱动类、数据库URL、用户名和密码等,还可以通过src来指定所需要的SQL脚本文件,或者直接使用文本内容的方式指定SQL脚本字符串
- echo:输出某个字符串
- exec:执行操作系统的特定命令,通常需要executable属性,用于指定想执行的命令。
- copy:用于复制文件或路径
- delete:用于删除文件或路径
- mkdir:用于创建文件夹
- move:用户移动文件或路径
%ANT_HOME%/manual/Tasks路径下包含了Ant所有task的详细介绍,可参考这些文档来了解各task所支持的属性和选项。
下面定义一个一份简单的生成文件,这份生成文件里包含了编译Java文件、运行Java程序、生成JAR包等常用的target,通常这份文件就可以非常方便地管理该项目。
1 |
|
注意:上面的生成文件中定义java task时制定了fork=”true”(或fork=”yes”效果也一样)。这表明启动另一个JVM进程来运行lee.HelloTest类,这个属性通常是个陷阱!如果不指定该属性,这属性值默认是false,这表明使用运行Ant的同一个JVM来运行Java程序,这将导致随着Ant工具执行完成,被运行的Java程序也不得不退出——这当然不是开发者希望看到的。
上面配置定义的生成文件里包含了5个target,这些target分别完成打印帮助信息、编译Java文件、运行Java程序、打包JAR包和清除编译生成的文件。执行这些target可使用如下命令。
- ant help:输出该生成文件的帮助信息。
- ant compile:编译Java文件。
- ant run:运行lee.HelloTest类。
- ant build:将classes路径下的所有class文件打包成app.jar,并放在dest目录下。
- ant clean:删除classes和dest目录。