Apache Ant学习笔记之二
©作者:zdon
•安装ant
从http://jakarta.apache.org/builds/ant/release/下载最新的编译好的ant发布版本,比如我下载的是apache-ant-1.6.1-bin.zip。将其解压到一个特定的目录,比如我将其解压到D:"apache-ant-1.6.1。
在系统环境变量中设ANT_HOME为ANT_HOME 应该设置为 Ant 根目录,即包含 bin 和 lib 目录的目录。在我的机器中为D:"apache-ant-1.6.1,在PATH变量中加入;%ANT_HOME%"bin,保存。确保 JAVA_HOME 环境变量设置为安装了 JDK 的目录,这样ANT就可以使用了。
在GNU/Linux上把以下配置加入/etc/profile中或者或者加入用户目录下的.bashrc文件中:
export ANT_HOME=/home/ant
export JAVA_HOME=/usr/java/j2sdk1.4.1
export PATH=$PATH:$JAVA_HOME/bin:$ANT_HOME/bin
|
•运行ant
没有指定任何参数时,Ant会在当前目录下查询build.xml文件。如果找到了就用该文件作为buildfile。要想让Ant使用其他的buildfile,可以用参数 -buildfile file,这里file指定了你想使用的buildfile。
使用ant -buildfile build.xml -logfile error.log来运行ant,就会将出错信息放入error.log中,方便查看。
重要参数:
·选项 -quite,告诉Ant运行时只输出少量的必要信息。而 -verbose,告诉Ant运行时要输出更多的信息。
·可以指定执行一个或多个target。当省略target时,Ant使用标签<project>的default属性所指定的target。
•build.xml文件基本结构
<project>
<property/> 全局变量的定义
<property/>...
<target name="1"> 任务组(tasks)
<javac></javac> 一项javac任务
...
<oneTask></ontTask> 一项其它任务
</target>
<target name="2">
<javac></javac>
...
<oneTask></ontTask>
</target>
</project>
|
配置文件由目标树构成。每个目标都包含了要执行的任务,其中任务就是可以执行的代码。每个目标都有唯一的名称和可选的相关性。目标相关性需要在执行目标任务列表之前执行。如:
<target name="compile" depends="JUNIT">
<mkdir dir="${build.dir}">
<javac srcdir="src/main/" destdir="${build.dir}">
<includ name="**/*.java/>
</javac>
|
</target>
|
在本例中,mkdir 是目标 compile 的任务。mkdir 是建立在 Ant 中的一个任务,用于创建目录。同时,在执行 compile 目标中的任务之前需要先运行 JUNIT 目标。这种类型的配置可以让您在一个配置中有多个树。
•ant生成文件主要概念
project代表一个项目
default:运行到名称为"dist"的target(任务组)
basedir:基准路径。
属性
一个project可以有很多的properties。可以在buildfile中用property task来设定,或在Ant之外设定。一个property有一个名字和一个值。property可用于task的属性值。这是通过将属性名放在"${"和"}"之间并放在属性值的位置来实现的。例如如果有一个property builddir的值是"build",这个property就可用于属性值:${builddir}/classes。这个值就可被解析为build/classes。
Path-like Structures
你可以用":"和";"作为分隔符,指定类似PATH和CLASSPATH的引用。Ant会把分隔符转换为当前系统所用的分隔符。
当需要指定类似路径的值时,可以使用嵌套元素。一般的形式是
<classpath>
<pathelement path="${classpath}"/>
<pathelement location="lib/helper.jar"/>
</classpath>
location属性指定了相对于project基目录的一个文件和目录,而path属性接受逗号或分号分隔的一个位置列表。path属性一般用作预定义的路径--其他情况下,应该用多个location属性。
为简洁起见,classpath标签支持自己的path和location属性。所以:
<classpath>
<pathelement path="${classpath}"/>
</classpath>
可以被简写作:
<classpath path="${classpath}"/>
也可通过<fileset>元素指定路径。构成一个fileset的多个文件加入path-like structure的顺序是未定的。
<classpath>
<pathelement path="${classpath}"/>
<fileset dir="lib">
<include name="**/*.jar"/>
</fileset>
<pathelement location="classes"/>
</classpath>
上面的例子构造了一个路径值包括:${classpath}的路径,跟着lib目录下的所有jar文件,接着是classes目录。
如果你想在多个task中使用相同的path-like structure,你可以用<path>元素定义他们(与target同级),然后通过id属性引用--参考Referencs例子。
path-like structure可能包括对另一个path-like structurede的引用(通过嵌套<path>元素):
<path id="base.path">
<pathelement path="${classpath}"/>
<fileset dir="lib">
<include name="**/*.jar"/>
</fileset>
<pathelement location="classes"/>
</path>
<path id="tests.path">
<path refid="base.path"/>
<pathelement location="testclasses"/>
</path>
前面所提的关于<classpath>的简洁写法对于<path>也是有效的,如:
<path id="tests.path">
<path refid="base.path"/>
<pathelement location="testclasses"/>
</path>
可写成:
<path id="base.path" path="${classpath}"/>
· 任务依赖
Ant的depends属性只指定了target应该被执行的顺序-如果被依赖的target无法运行,这种depends对于指定了依赖关系的target就没有影响。Ant会依照depends属性中target出现的顺序(从左到右)依次执行每个target。然而,要记住的是只要某个target依赖于一个target,后者就会被先执行。
<target name="A"/>
<target name="B" depends="A"/>
<target name="C" depends="B"/>
<target name="D" depends="C,B,A"/>
假定我们要执行target D。从它的依赖属性来看,你可能认为先执行C,然后B,最后A被执行。错了,C依赖于B,B依赖于A,所以先执行A,然后B,然后C,最后D被执行。一个target只能被执行一次,即时有多个target依赖于它。
· 注释用<!-- -->方式
· 一般一个ant生成文件应该完成
· 定义全局变量
· 初始化,主要是建立目录
· 编译 (已有)
· 打包为jar
· 建立API documentation
· 生成distribution产品 多种任务
|
•最简单的例子:
<?xml version="1.0" encoding="GB2312"?>
<!-- edited with XMLSPY v5 U (http://www.xmlspy.com) by zdon -->
<project name="testExampleProject" default="makejar" basedir=".">
<description>一个简单的创建项目的build练习</description>
<!-- 为此build设置全局化的属性 -->
<!--主要的系统环境属性-->
<property environment="env"/>
<property name="java.home" value="${env.JAVA_HOME}"/>
<property name="ant.home" value="${env.ANT_HOME}"/>
<!--主要的app环境属性-->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<!--app用到的lib-->
<property name="lib.dir" value="zdon-example/WEB-INF/lib"/>
<path id="classpath">
<!--本项目用到的所有包,将在使用javac任务时引用-->
<pathelement location="${build}"/>
<pathelement path="${java.home}/lib/tools.jar"/>
<pathelement path="${lib.dir}/classes12.jar"/>
<pathelement path="${lib.dir}/servlet.jar"/>
<pathelement path="${lib.dir}/commons-lang.jar"/>
<pathelement path="${lib.dir}/commons-logging.jar"/>
<pathelement path="${lib.dir}/commons-beanutils.jar"/>
<pathelement path="${lib.dir}/commons-collections.jar"/>
<pathelement path="${lib.dir}/log4j-1.2.8.jar"/>
<pathelement path="${lib.dir}/cglib.jar"/>
<pathelement path="${lib.dir}/struts.jar"/>
<pathelement path="${lib.dir}/hibernate2.jar"/>
</path>
<!-- 初始化任务 -->
<target name="init" description="初始化任务,创建编译目录">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
<mkdir dir="${dist}"/>
</target>
<target name="compile" depends="init" description="编译源文件 ">
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}">
<classpath refid="classpath"/>
</javac>
</target>
<target name="makejar" depends="init,compile" description="将所有编译好的文件打包 ">
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<jar jarfile="${dist}/boncexample-${DSTAMP}.jar" basedir="${build}"/>
</target>
<target name="clean" description="清场">
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
|
•基本任务参考:
1.引用外部的properties文件:
<property file="${basedir}/build.properties" />
|
这样做是为了方便工程人员或客户,使他们不必去看xml格式的build文件就可以做一些简单的配置工作。
2.CLASSPATH设置:
<path id="classpath">
<pathelement path="${jsdk_jar}"/>
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
</path>
等价于:CLASSPATH=/path/to/resin/lib/jsdk23.jar; /path/to/project/lib/*.jar;
|
3.创建与删除目录:
<!-- create directories -->
<mkdir dir="${build.src}"/>
<mkdir dir="${build.dest}"/>
|
<delete dir="${root}/dist/"/>
|
4.拷贝文件:
<!-- copy src files -->
<copy todir="${build.src}">
<fileset dir="${src.dir}"/>
</copy>
|
单个文件
<copy file="${deploy_path}/classjar.jar" todir="${root}/dist/"/>
|
5.进行编译:
<target name="compile" depends="init" description="编译源文件 ">
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}">
<classpath refid="classpath"/>
</javac>
</target>
|
注意:编译时的CLASSPATH环境通过<classpath refid="classpath"/>
的方式引用了一个path对象。
6.打包任务:jar
对应用打包生成项目所写名的.jar文件
<!-- ======================================= -->
<!-- Creates the class package -->
<!-- ======================================= -->
<target name="jar" depends="build">
<jar jarfile="${lib.dir}/${name}.jar"
basedir="${build.dest}"
includes="**"/>
</target>
|
打包时使用时间戳
<target name="makejar" depends="init,compile" description="将所有编译好的文件打包 ">
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<jar jarfile="${dist}/boncexample-${DSTAMP}.jar" basedir="${build}"/>
</target>
|
7.生成JAVADOC文档:
<!--=================================== -->
<!-- Creates the API documentation -->
<!--=================================== -->
<target name="javadoc" depends="build">
<mkdir dir="${build.javadocs}"/>
<javadoc packagenames="${packages}"
sourcepath="${build.src}"
destdir="${build.javadocs}"
author="true"
version="true"
use="true"
splitindex="true"
windowtitle="${Name} API"
doctitle="${Name}">
<classpath refid="classpath"/>
</javadoc>
</target>
|
8.清空临时编译文件:
<!--================================== -->
<!-- Clean targets -->
<!--================================== -->
<target name="clean" depends="init">
<delete dir="${build.src}"/>
<delete dir="${build.dest}/org"/>
<delete dir="${build.dest}/com"/>
<delete>
<fileset dir="${build.dest}" includes="**/*.class"/>
</delete>
</target>
|
9.测试任务:JUnit测试
<!-- 编译Junit文件 -->
<target name="compilejunit" depends="compilesrc">
<mkdir dir="${dist.junit}"/>
<javac destdir="${dist.junit}" deprecation="on">
<src path="${src.junit}"/>
<classpath refid="classpath"/>
</javac>
</target>
|
<!-- 运行junit -->
<target name="junit" depends="compilejunit">
<mkdir dir="${doc.junitReport}"/>
<copy todir="${dist.junit}">
<fileset dir="junit_lib">
<exclude name="**/*.jar"/>
</fileset>
<fileset dir="${src.code}">
<include name="fog.hbm.xml"/>
</fileset>
</copy>
<junit printsummary="yes" haltonfailure="no">
<classpath>
<path refid="classpath"/>
<pathelement location="${dist.junit}"/>
</classpath>
<formatter type="brief" usefile="false"/>
<formatter type="xml"/>
<batchtest todir="${doc.junitReport}">
<fileset dir="${dist.junit}" includes="**/*Test.class" />
</batchtest>
</junit>
<junitreport todir="${doc.junitReport}">
<fileset dir="${doc.junitReport}">
<include name="TEST*-*.xml"/>
</fileset>
<report format="frames" styledir="${junit.styleDir}" todir="${doc.junitReport}"/>
</junitreport>
</target>
|
或者:
<target name="junit" depends="compile">
<junit printsummary="yes" fork="yes" haltonfailure="no">
<classpath>
<pathelement location="${bin.dir}"/>
<pathelement path="${java.class.path}"/>
</classpath>
<formatter type="xml"/>
<batchtest todir="${juit.report.dir}/xml/${DSTAMP}">
<fileset dir="${bin.dir}">
<include name="**/*Test.class" />
</fileset>
</batchtest>
</junit>
<junitreport todir="${juit.report.dir}/xml/${DSTAMP}">
<fileset dir="${juit.report.dir}/xml/${DSTAMP}">
<include name="TEST-*.xml"/>
</fileset>
<report format="noframes" todir="${juit.report.dir}/html/${DSTAMP}"/>
</junitreport>
</target>
|
10.代码风格检查任务:CheckStyle
<!-- 运行checkstyle检查代码规范 -->
<target name="checkstyle" depends="init">
<mkdir dir="${doc.checkstyleReport}"/>
<checkstyle config="${checkstyle.config}">
<fileset dir="${src.code}" includes="**/*.java"/>
<formatter type="plain"/>
<formatter type="xml" toFile="${doc.checkstyleReport}/checkstyle_report.xml"/>
</checkstyle>
<style in="${doc.checkstyleReport}/checkstyle_report.xml" out="${doc.checkstyleReport}/checkstyle_report.html" style="${checkstyle.xsl}"/>
</target>
|
11.对数据库的操作:
<!-- Oracle -->
<target name="db_setup_oracle" description="Database setup for Oracle">
<antcall target="check_params_results"/>
<sql driver="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@192.168.0.1:1521:oa"
userid="oa" password="oa"
onerror="continue"
print="yes"
src="./demo.ddl"/>
</target>
|
注意:demo.ddl中写的是sql语句
12.运行JAVA程序:
<!--(10)运行(args中是参数,随应用程序的具体情况有所不同)->
<target name="simplesql" depends="compile,db_setup_oracle">
<java classname="examples.jdbc.oracle.simplesql"
fork="yes" failonerror="yes"
args="-user zrb
-password zrb
"/>
</target>
|
13.使用样式表来查看ant生成脚本:
使用样式表来查看ant脚本,准备好这个样式表之后,可将其放在某个浏览器能够访问的地方。最后一步是向 Ant 脚本中加入指令。这些指令告诉浏览器在显示该文档的时候使用您的样式表。请将下面高亮显示的部分拷贝到 Ant 脚本的最上面,然后用您的样式表的位置替换 href 属性的值。
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl"
href="./examples/example2/ant2html.xsl"?>
<project name="Example2" default="main" basedir=".">
<!-- The rest of the Ant script goes here. -- >
</project>
|
这样处理后就会有以下好处:
· 提供内容列表,方便用户迅速地找到脚本中相应的节
· 对使用到的所有属性和目标都按字母排序并分组
· 在目标及其所依赖的部分之间提供导航链接
· 显示构造出某个特定目标的任务
|
另一个一个可以生成框架的样式表。
14.使用ant来调用RetroGuard混淆器
<target name="obfuscate" description="使用混淆器" depends="package">
<java fork="yes" classname="RetroGuard" classpath="${obfuscate.lib}">
<arg line="${build.dir.bin.jarunobfus}"/>
<arg line="${build.dir.bin.jar}"/>
<arg line="${obfuscator.script}"/>
</java>
</target>
|
混淆器用的是Open Source的RetroGuard.在http://www.retrologic.com/下载
15.使用时间戳:
一般是在init中的第一行写一个<stamp />,声明。说他是声明是因为如果你想在你的build脚本中使用当前的时间日期的话就必须指定这个,然后在后文中就可以使用${DSTAMP}这样的标签了。〈未完〉