sowill / Java / Ant简介

分享

   

Ant简介

2005-12-11  sowill
Ant 是一个纯Java工具,所以,要运行它,首先需要安装一个Java虚拟机(JVM)。你可能已经安装了一个JVM,但是如果还没有,你可以从 上面免费下载一个。然后,从 下载Ant的二进制版本。将Ant压缩文档unzip或者untar(取决于你的系统平台)到你选择的安装目录(Windows下面通常是c:\Ant,UNIX下面通常是/usr/local/ant)。

    在软件安装完成之后,必须指示你的系统去找到这两个目录来启动那些应用程序。通过将这两个工具的bin目录放置到你的PATH环境变量中做到这一点。此外,你应该定义JAVA_HOME和ANT_HOME环境变量来让那些工具了解它们的位置。

如果你用的系统是Windows,那么你需要在autoexec.bat文件中加入以下数行语句:

set JAVA_HOME=<JAVA_HOME>
set ANT_HOME=<ANT_HOME>
set PATH=%PATH%;<JAVA_HOME>\bin;<ANT_HOME>\bin

      重启机器以完成安装。如果系统报告说传递了太多的参数到SET命令,那么可能是PATH中包含了空格。要解决这个问题,就在一个单一行中定义PATH,并且将它用双引号引起来。

      如果你的系统是UNIX并且正在使用Bash外壳,在~/.bash_profile文件中加入以下数行:

JAVA_HOME=<JAVA_HOME>
ANT_HOME=<ANT_HOME>
PATH=$PATH:<JAVA_HOME>/bin:<ANT_HOME>/bin
export JAVA_HOME ANT_HOME PATH

    运用其他外壳的用户应该改写这段脚本并且编辑合适的配置文件。为更新系统环境,输入.~/.bash_profile。为测试是否成功安装,在终端窗口输入java 和ant 命令。系统会发现这些命令并运行之。

    Ant像Make一样工作。进入要运行的buildfile(其缺省的名字为build.xml)所在的目录,然后输入ant。要运行另外一个目录中的buildfile或者名字不是build.xml的buildfile,需要使用-buildfile参数。Ant也可以通过使用-find参数在文件系统中递归地找到所需的buildfile,因此可以从工程中的任意地方启动Ant。要显示关于命令行ant参数的帮助,请输入 ant -help。

Ant简介

作者:Michel Casabianca

本文讲述如何使用这个具有极大价值的工具(Ant)来构建和部署Java工程。

    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语法。

本文将向你展示一个典型的Ant文件,它使用了很多的Ant基本任务。

一个典型的Ant工程

    Ant使用用XML编写的、称作bulidfile的工具来开展它的工作。让我们考虑一个源文件在src目录中、类库(包括JAR文件)在lib目录中、API文档在doc/api目录中的典型Java工程。我们可以利用如下的Ant buildfile来构建这个工程。

<?xml version="1.0"?>
<project name="typical" default="all" basedir=".">
 <property name="name" value="typical"/>
 <property name="src" value="src"/>
 <property name="lib" value="lib"/>
 <property name="api" value="doc/api"/>

 <property name="tmp" value="tmp"/>
 <property name="classpath" value="${lib}/${name}.jar"/>
 <property name="main" value="test.Main"/>

 <target name="bin"
         description="Compile Java source files">
  <javac srcdir="${src}"
         destdir="${tmp}"
         debug="on"

         deprecation="on"/>
 </target>

 <target name="jar" depends="bin"
         description="Build jar file">
  <jar jarfile="${lib}/${name}.jar"
       basedir="${tmp}"/>
 </target>

 <target name="run" depends="jar"

         description="Run the program">
  <java classname="${main}"
        classpath="${classpath}"/>
 </target>
 <target name="api"
         description="Generate API documentation">
  <javadoc sourcepath="${src}"
           destdir="${api}"
           packagenames="test.*"/>
 </target>


 <target name="clean"
         description="Clean generated files">
  <delete dir="${tmp}"/>
  <mkdir dir="${tmp}"/>
 </target>

 <target name="all" depends="clean,jar,api"/>

</project>
                  

也许这里的语法看起来非常冗长(你可以使用Make写一个短的多的buildfile),但是Ant buildfile的优点是其可读性好。

    buildfile的内容被包含在元素中。工程一般有一套工程属性,带有一些区--由一些Ant任务诸如编译源代码、生成目录和生成JAR文件等组成。

    工程和属性。在 元素下面首先可以找到属性。这些属性元素类似于变量。你通常可以按照任务在工程内的任何地方使用属性值,这些任务是通过使用表达式 $ {属性名(property-name)} 在< target> 元素中定义的。举例来说,在上述的buildfile 例子中,值${src}会被解析成src,因为我们在属性区中对它是如此定义的。在我们的buildfile中,我们使用${src}属性作为在javac任务中的srcdir的特性的值。

   当在命令行中用句法-Dproperty=value来调用Ant的时候,可能会定义或者重写属性。比如说,如果你想将src的值设定为source-directory,你可以在命令行中键入ant DDsrc=sourc_directory。此外,属性是恒定的,所以一旦被定义,就不能修改它们的值。

   目标和任务。目标(target)元素定义了一套指令来实现某类工作。可以把它们比作由很多任务构成的程序函数(与编程指令相比)。举例来说,在上述的buildfile例子中,名为jar的目标(具有属性name=jar的元素)包含有一个单一的任务以从类文件来生成JAR文件。这个例子中只是凑巧目标名称和任务名称相同,但是这个并不是必需的--目标元素名称是由创建者选择的,但是任务名称是固定的,并且与那些定义在Ant标记中引用的目标名相匹配。这个特殊的目标(我们的目标)依赖于bin 目标(比如说,depends=bin),这意味着如果目标 jar被调用,那么它就会首先调用bin目标(如果bin目标还没有被执行)。当调用Ant时,你可以传递一个目标在命令行上运行。比如说,通过在命令行输入命令ant jar调用Ant,可以运行目标jar。如果不指定一个目标而调用Ant,在工程的默认属性中指定的目标就会被运行(在本例中,是"all"目标)。你也可以通过用空格分隔目标的办法来调用带有多个目标的Ant。

目标及其任务

  如前所述,Ant bulidfile是一个处理工程构建或部署给定阶段的目标的集合。在这里我将描述在我们的示例buildfile中使用到的目标,并详细说明在使用这些目标及其相关的任务的时候会碰到的一些常见问题。你可以根据自身的需要快速地定制这里所展示的bulidfile。以下的例子描述了这些通过使用我们的Ant bulidfile完成这些工作的步骤:

1. 编译Java源文件
2. 创建JAR文件
3. 运行程序
4. 生成API文档
5. 清除生成的class(类)文件

1. 编译Java源文件

这个目标的使用可能是最广泛的。通常由以下代码来实现:

<target name="bin" description="Compile Java source files">

  <javac srcdir="${src}"
         destdir="${tmp}"
         debug="on"
         deprecation="on"/>
 </target>
                  

     这个目标包括一个单一的javac任务,这个任务就是编译Java源文件。在上面的这个例子中使用的属性非常简单明了:srcdir是存放源文件的目录,destdir是存放所生成的类文件的目录。最后两个属性是用于javac编译选项的。注意到optimize属性(这里没有使用)没有什么用,所以最新的Java编译器没有将该属性放入其中。当需要类库进行编译时,你应该添加一个classpath(类路径)属性以便在其中列出JAR文件或者目录。可以在UNIX或者Windows系统下面写一个Ant路径,其中使用冒号或者分号作为路径的分隔标记,使用斜线或者反斜线作为文件的分隔标记。这样,定义为lib/foo.jar:lib/bar.jar的classpath在UNIX下不用修改就可以直接使用,而在Windows下就会被自动转换成lib\foo.jar;lib\bar.jar。

   这个任务力图使用与JDK一起提供的编译器。该编译器是带有其自有类的 Java程序,其自有类存在于tools.jar文件中(该文件位于lib目录中)。这样,tools.jar文件必须在classpath中被指定。在很多操作系统中(包括Solaris和Linux),这个不成其为问题,在使用javac任务时,如果Ant不能使用这个标准编译器的话,它就会抗议。为了解决该问题,只要简单地将lib/tools.jar文件与jre/lib/ext/tools.jar做一个链接就可以了。

2. 创建一个JAR文件

这个任务从Java类(以及诸如图片或者本地文件等其他资源)生成一个JAR文件。在我们的示例buildfile中,通过如下代码实现:

<target name="jar" depends="bin"
         description="Build jar file">
  <jar jarfile="${lib}/${name}.jar" basedir="${tmp}"/>
 </target>
                  

     jar元素的属性非常明显。当你想要包括文档库中的其他文件时,你可以在任务中放置fileset元素。如同它们的名字所暗示的那样,那些元素(并不是任务本身)定义了一系列的文件。让我们设想一下,如果你想要引入一些位于img目录中的PNG(Portable Network Graphics)格式的图片文件,你应该编写如下代码:

<target name="jar" depends="bin"
        description="Build jar file">
 <jar jarfile="${lib}/${name}.jar"
      basedir="${tmp}">
  <fileset dir="img" includes="*.png"/>

 </jar>
</target>
                  

   dir属性指出了文件的基本目录;而includes包含了一个表达式,该表达式定义了一些文件以包括在fileset中。那些表达式有一个与shell命令非常接近的句法,"*"字符匹配零个或者多个字符而"?"只匹配一个字符。你可以在目录树中(包括零)使用表达式"**"来替代任意数目的目录。比如说,如果在上述的例子中要包括的图片位于img的任意一个子目录中,那么应该在jar元素中放置如下所示的fileset:

<fileset dir="img" includes="**/*.png"/> 
                  

    也可以使用excludes属性把文件从fileset中排除。比如说,要包括在img目录中的除了.ida类型的所有其他文件,那么可以按照如下方式编写fileset:

<fileset dir="img" excludes="**/*.dia"/>
                      

    缺省情况下,某些文件是被所有的fileset排除在外的,这些文件是编辑器生成的备份文件(例如UNIX下的**/*~文件)和版本控制目录(例如**/CVS/*)。如果要告诉Ant你不想排除那些文件,那么就需要在fileset元素中加入属性defaultexcludes="false"。

Ant也可以处理用于打包Web应用程序的WAR文件和用于更复杂应用程序的EAR文件,这些复杂的应用程序经常结合使用JSP、Servlets和EJB。Ant有专门的任务来生成WAR和EAR文件。那些任务是JAR任务的扩展,定义了新的嵌套元素和属性。WAR任务定义了等嵌套元素,这些元素定义特别的fileset的元素。包括在那些fileset中的文件将在文档库的WEB-INF/lib、WEB-INF/classes和WEB-INF以及META-INF目录中结束。同时,它也为该文档(WEB-INF/web.xml)的部署描述符定义webxml属性。

EAR任务使用元素来将文件放入文档的META-INF目录,将appxml属性用于部署描述符(META-INF/application.xml)。

3. 运行程序

为运行Java应用程序,需要使用java任务,如下面的代码所示:

<target name="run" depends="jar"
         description="Run the program">
  <java classname="${main}"
        classpath="${classpath}"/>
 </target>
                  

classname定义了包括main()方法运行程序的打包的类的名称,classpath包含了运行它的类路径。可以使用嵌套的arg元素传递命令行参数,或者通过嵌套sysproperty元素定义系统属性。这两种动作执行起来都会非常快,因为缺省情况下,该程序运行在运行Ant的虚拟机(可以使用fork属性让Ant启动一个新的虚拟机)上。

元素中,通过使用classpath属性指定了类路径。用或者子元素(subelement)嵌套也是可以的。比如说,要在lib目录下包括在classpath属性中的条目、目录类以及所有的JAR文件,可以编写如下代码:

<java classname="${main}">
 <classpath>
    <pathelement path="${classpath}"/>
    <pathelement location="classes"/>
    <fileset dir="lib" includes="*.jar"/>
   </classpath>
  </java>
                  

如果要重用一个路径,我们可以在元素中定义它及其ID,并且在元素引用它们。举例来说,如果我们想重用在上面定义的路径,可以按照如下所示编写代码:

	 <path id="run.path">
	   <pathelement path="${classpath}"/>
	   <pathelement location="classes"/>
	   <fileset dir="lib" includes="*.jar"/>	 
	 </path>
                  

4. 生成API文档

这里的目标是通过使用javadoc生成API文档。大体说来,这是由一个单一javadoc任务构成的简易目标,代码如下:

  <target name="api"
         description="Generate API documentation">
    <javadoc sourcepath="${src}"
           destdir="${api}"
           packagenames="test.*"/>
   </target>
                  

sourcepath和destdi是显而易见的属性。packagenames属性是一个以逗号分隔的、提供文档的包列表。虽然Java的import语句不是递归的,但是packagenames属性却是递归的。这意味着语句packagenames="test.*"可以为test包、test.foo包和test.foo.bar包提供文档,但是不会为foo或者foo.test包提供文档。

可以使用windowtitle、doctitle、header、footer和bottom这些包含HTML代码的属性定义窗口和文档的标题以及所生成页面的页眉、页脚和底行。注意:应该用相应的XML实体(< 和")来代替XML格式字符(< 和 ")。也可以用link属性为文档链接指定一个URL。我们会说你用String参数编写了一个方法。对于一个生成的不带有link属性的文档,在方法文档中你就只有一个纯文本java.lang.String。当使用一个合适的link属性时,这将显示为一个到Sun的java.lang.String类的文档的链接。

5. 清除生成的类文件

该目标清除生成的类文件。比如说,要清除在tmp子目录中的类文件(以及其他资源),可以编写如下代码:

<target name="clean"
         description="Clean generated files">
  <delete dir="${tmp}"/>
  <mkdir dir="${tmp}"/>
 </target>
                  

清除类文件总是一个很好的主意,因为它可以在将来的编译中避免错误的相关性问题。假设你在类A中定义了一个常量foo,并且在类B中使用它。当你编译这些Java源文件的时候,foo的值被嵌入在B的类文件中。如果你修改foo的值,并且重新编译(没有删除类文件),javac任务就不会编译类B,因为它的源文件比相应的类要旧,因此旧的值将保持不变。即便用javac使用depend属性也不能解决这个问题,因为Java编译器的这个选择是一种错误。Jikes的相关性检查较好,但是你应该重新构建所有的类文件,这样才是最快的办法。

当你在HTML中用样式表时会遇到类似的问题。style任务不检查要使用样式表的日期。这样的话,如果你对那些文件进行操作,该任务将不会生成目标文件(通常是HTML文件)。你可以通过使用force属性来强制性地生成文件,但是这样通常是效率极低的。在这种情况下,通过下面的clean目标可以删除所生成的HTML文件(在doc属性目录中):

 <target name="clean">
   <delete dir="${tmp}"/>
   <mkdir dir="${tmp}"/>
   <delete><fileset dir="${doc}" includes="*.html"/></delete>
 </target>
                  

为解决这些相关性问题,当你生成新版本的文件时,应该不时地运行clean目标。

接下来:

在第二部分,我们将讨论一些更高级的Ant任务,诸如从源代码控制系统中检查文件、用标记操纵数据库、用JUnit运行unit测试、部署工程以供测试或者部署生产服务器等。

Michel Casabianca (casa@sweetohm.net) 是In-Fusio的软件工程师。In-Fusio是一家为移动用户提供游戏服务的法国公司。同时,Michel Casabianca还是"XML Pocket Reference"一书(O‘Reilly出版, 2001年)的合著者。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。

    来自: sowill > 《Java》

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多
    喜欢该文的人也喜欢 更多

    ×
    ×

    ¥.00

    微信或支付宝扫码支付:

    开通即同意《个图VIP服务协议》

    全部>>