作为现在Java构建工具中事实上的标准,Ant被设计成可以通过Java类进行扩展,而且只需要很少的Java代码,就可以编写一个新的Ant任务。其实编写一个 Ant任务非常简单,只需要编写一个带有一个execute()方法的Java类就行了。
package com.hsp.tasks;
public class DefAntTask{
public void execute(){
System.out.println("def Ant task....");
}
}
这个Java不需要扩展任何基类,只需要一个方法就行:execute( )。但这个方法必须是公有的(public),没有参数,而这个类必须能通过无参的构造函数实例化。这个方法可以有返回值,但是会被忽略并且产生一个警告信息。任务在执行过程中可以有System.out和System.err的输出,但是会被Ant截获并按照适当的日志级别输出到控制台,当然也可以配置让日志输出到文件中。
<taskdef>标签用于自定义一些任务,从而将第三方的任务集成到构建文件中。你可以在目标(<target>)之外声明<taskdef>,以便把这些任务定义成全局任务,这样在就可以像使用 Ant 的核心任务一样使用这个自定义的任务了。不过任务的类文件必须位于其可见的classpath内。为了可以在一个构建过程中使用编译过的任务,<taskdef>必须出现在编译之后。如下build.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- ======================================================================
2015年3月29日 下午10:20:43
project
description
gaoweigang
====================================================================== -->
<project name="project" default="execute">
<description>
description
</description>
<!--Ant执行日志-->
<record name="D:/log4j.log" loglevel="info" append="no" action="start"/>
<property name="build.dir" location="build"></property>
<target name="init">
<mkdir dir="${build.dir}"/>
</target>
<target name="compile" depends="init">
<!--编译 实现的自定义任务DefAntTask.java,生成的class文件位于${build.dir}中-->
<javac srcdir="src" destdir="${build.dir}" ></javac>
</target>
<target name="execute" depends="compile">
<!--定义任务-->
<taskdef name="DefAntTask" classname="com.hsp.tasks.DefAntTask" classpath="${build.dir}" />
<!--调用执行自定义任务-->
<DefAntTask/>
</target>
</project>
1.1 任务的生命周期
下面是Ant任务的生命周期,构建过程从装载Ant和解析构建文件开始:
- 当Ant 解析构建文件时,对文件中声明的每个任务,通过不带参数的构造函数建立一个恰当的Task的子类的实例。
- Ant传递一些信息给任务,包括任务所在的工程和目标、以及其他一些次要细节,例如它出现在构建文件中的行数。
- Ant调用Task类的init( )函数。大多数任务都不重写这个函数。
- Ant按照自己的方式,一次执行目标(就是依据depends属性指定的顺序) 一个目标中的任务得以逐个执行。对于每一个任务,Ant先根据构建文件的属性和元素的值对其进行配置,然后调用其execute( )函数。
Ant内部使用TaskAdapter,一个派生自org.apache.tools.ant.Task的任务适配器来处理那些不扩展Task类的任务。适配器中有个Object实例,并会调用任务对象的execute( )方法。
2.Ant API
现在我们就来了解一下Ant中主要的API,作为开发者的我们需要经常和它们打交道。
2.1 Task
抽象类org.apache.tools.ant.Task是Ant任务最常用的基类,是Ant构建过程中的主要工作单元。Task类通过保护类型成员变量project,提供对project对象的访问。还有log方法则可以将输出传给Ant进程。Task类中主要是init()和execute()方法需要重载,而log()方法(log(String msg, int msgLevel)和log(String msg))主要是用于调用,它是调用project对象的log函数。其中有五个日志级别(按优先级排列):
- MSG_ERR
- MSG_WARN
- MSG_INFO
- MSG_VERBOSE
- MSG_DEBUG
2.2 Project
String getProperty(String name):返回某个Ant特性的值,如果不存在这个特性,则返回null。
Void setNewProperty(String name, String value):给一个特性赋值,但要记住Ant中的特性是不可变更的。所以这个方法在这个特性存在的情况下,就什么都不作。
File getBaseDir():这个函数返回工程的基准目录(base directory)。它对解析相对路径非常有用,虽然在实际中用的并不多,因为Ant的文件和路径已经具有了自动展开的功能。
File resolveFile(String filename):这个函数根据文件名返回带有绝对路径的File对象。假如文件名是个相对值,则它会根据工程的基准目录进行解析。
2.3 Path
String toString():返回经过完全解析的、且平台相关的完整路径信息。
static String[] translatePath(Project project , String path):这个工具函数根据某个路径分解得到路径元素数组,那个路径包含着由冒号或者分号分隔开来的路径元素。
int size():返回Path实例中路径元素的数量。
String[] list():返回Path实例中路径元素数组。
2.4 Fileset
2.5 DirectoryScanner
2.6 EnumeratedAttribute
2.7 FileUtils
3.属性
XML属性其实就是一个名值对。假如你现在有一个 任务,仅有一个属性name:
<DefAntTask name=”gaoweigang”/>
这个任务有个setName的函数:
private String name;
public void setName(String name) {
this.name = name;
}
这和JavaBean的命名风格很相似,每个特性都对应一个读写器(setter/getter)。属性的内省机制支持Java的基本类型和包装类型,而类型之间的转换出现错误的话,将抛出NumberFormatException异常,构建过程将停止。
通过实现一个以java.io.File参数的设值函数,Ant提供了对文件或者目录属性内置的支持,它可以将构建文件中的相对目录解析为绝对路径。
<DefAntTask destdir =”descFile”/>
对应的任务就实现了setDestDir函数:
private File destFile;
public void setDestDir(File destFile) {
this.destFile = destFile;
}
例如:工程目录结构如下:
![Ant自定义任务 Example](http://img.e-com-net.com/image/product/11af61523bfb447e845c7d72b6d6e149.png)
①实现自定义任务
package com.hsp.tasks;
import java.io.File;
public class DefAntTask{
private String name;
private String password;
private File destfile;
public void execute(){
System.out.println("def Ant task....");
System.out.println("name:"+name);
System.out.println("password:"+password);
System.out.println(destfile.getAbsolutePath());
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public File getDestfile() {
return destfile;
}
public void setDestfile(File destfile) {
this.destfile = destfile;
}
}
②在build.xml使用自定义任务
<?xml version="1.0" encoding="UTF-8"?>
<!-- ======================================================================
2015年3月29日 下午10:20:43
project
description
gaoweigang
====================================================================== -->
<project name="project" default="execute">
<description>
description
</description>
<!--Ant执行日志-->
<record name="D:/log4j.log" loglevel="info" append="no" action="start"/>
<property name="build.dir" location="build"></property>
<target name="init">
<mkdir dir="${build.dir}"/>
</target>
<target name="compile" depends="init">
<!--编译 实现的自定义任务DefAntTask.java,生成的class文件位于${build.dir}中-->
<javac srcdir="src" destdir="${build.dir}" ></javac>
</target>
<target name="execute" depends="compile">
<!--定义任务-->
<taskdef name="DefAntTask" classname="com.hsp.tasks.DefAntTask" classpath="${build.dir}" />
<!--调用执行自定义任务,并且向任务类传递属性-->
<DefAntTask name="gaoweigang" password="123456" destfile="./src"/>
</target>
</project>
③执行构建,日志输出如下:
![Ant自定义任务 Example](http://img.e-com-net.com/image/product/776bbdf4edaa4a2e9a81981990ae8d80.png)
<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="builddatabase">
<!-- ================================================================== -->
<!-- 其他配置 -->
<!-- ================================================================== -->
<property file="build_database.properties" />
<path id="toolslib">
<!--定义java编译结果.class文件的跟目录 -->
<pathelement location="${depend_classes_folder}" />
<!-- 需要使用的第三方jar存放目录 -->
<fileset dir="${depend_libs_folder}">
<include name="**/*.jar" />
</fileset>
</path>
<target name="builddatabase">
<taskdef name="buildToolTask" classname="com.ling2.build.ant.BuildToolTask"
classpathref="toolslib" />
<!-- destdir属性可以在各输出属性中分别指定,这里是全局指定 -->
<buildToolTask database_configfile="${database_configfile}"
config_rootfolder="${config_rootfolder}" errolist_configfile="${errolist_configfile}"
svn_rootfolder="${depend_svn_rootfolder}" result_rootfolder="${depend_result_rootfolder}"
publish_filename="${publish_filename}" database_name="${database_name}">
<hkTask />
</buildToolTask>
</target>
</project>
参考:http://blog.csdn.net/jackkp_catus/article/details/2295612