现在的位置: 首页 > 综合 > 正文

ant学习笔记—自定义Ant任务

2013年08月31日 ⁄ 综合 ⁄ 共 5744字 ⁄ 字号 评论关闭

作为现在Java构建工具中事实上的标准,Ant被设计成可以通过Java类进行扩展,而且只需要很少的Java代码,就可以编写一个新的Ant任务。

其实编写一个 Ant任务非常简单,只需要编写一个带有一个execute()方法的Java类就行了。

 

       Package  org.cactus.ant.tasks

       Public  class  SimpleTask{

              Public  void  execute(){

       System.out.println(“Simple  Task!”);

}

}

 

这个Java不需要扩展任何基类,只需要一个方法就行:execute( )。但这个方法必须是公有的(public),没有参数,而这个类必须能通过无参的构造函数实例化。这个方法可以有返回值,但是会被忽略并且产生一个警告信息。任务在执行过程中可以有System.outSystem.err的输出,但是会被Ant截获并按照适当的日志级别写入相应的日志。

<taskdef>标签用于自定义一些任务,从而将第三方的任务集成到构建文件中。你可以在目标(<target>)之外声明<typedef>,以便把这些任务定义成全局任务。不过任务的类文件必须位于其可见的classpath内。为了可以在同一个构建过程中使用编译过的任务,<taskdef>必须出现在编译之后

 

<?xml  version=”1.0”?>

<project  name=”tasks”  default=”main”>

       <property  name=”build.dir”  location=”build”/>

       <target  name=”init”>

              <mkdir  dir=”${build.dir}”>

       </target>

       <target  name=”compile”  depends=”init”>

              <javac  srcdir=”src”  destdir=”${build.dir}”/>

       </target>

       <target  name=”simpletask”  depends=”compile”>

              <taskdef  name=”simpletask”

  classname=”org.example.antbook.tasks.SimpleTask” classpath=”${build.dir}”>

                     <simpletask/>

</target>

<target  name=”clean”>

       <delete  dir=”${build.dir}”>

</target>

<target  name=”main”  depends=”simpletask”/>

       </project>

 

1.1   任务的生命周期

下面是Ant任务的生命周期,构建过程从装载Ant和解析构建文件开始:

l         Ant 解析构建文件时,对文件中声明的每个任务,通过不带参数的构造函数建立一个恰当的Task的子类的实例。

l         Ant传递一些信息给任务,包括任务所在的工程和目标、以及其他一些次要细节,例如它出现在构建文件中的行数。

l         Ant调用Task类的init( )函数。大多数任务都不重写这个函数。

l         Ant按照自己的方式,一次执行目标(就是依据depends属性指定的顺序)。

l         一个目标中的任务得以逐个执行。对于每一个任务,Ant先根据构建文件的属性和元素的值对其进行配置,然后调用其execute( )函数。

Ant内部使用TaskAdapter,一个派生自org.apache.tools.ant.Task的任务适配器来处理那些不扩展Task类的任务。适配器中有个Object实例,并会调用任务对象的execute( )方法。

2Ant API

现在我们就来了解一下Ant中主要的API,作为开发者的我们需要经常和它们打交道。

2.1 Task

抽象类org.apache.tools.ant.TaskAnt任务最常用的基类,是Ant构建过程中的主要工作单元。Task类通过保护类型成员变量project,提供对project对象的访问。还有log方法则可以将输出传给Ant进程。Task类中主要是init()execute()方法需要重载,而log()方法(log(String msg, int msgLevel)log(String msg))主要是用于调用,它是调用project对象的log函数。其中有五个日志级别(按优先级排列):

l         MSG_ERR

l         MSG_WARN

l         MSG_INFO

l         MSG_VERBOSE

l         MSG_DEBUG

2.2 Project

l         String  getProperty(String name)返回某个Ant特性的值,如果不存在这个特性,则返回null

l         Void  setNewProperty(String name,  String value)给一个特性赋值,但要记住Ant中的特性是不可变更的。所以这个方法在这个特性存在的情况下,就什么都不作。

l         File getBaseDir():这个函数返回工程的基准目录(base directory)。它对解析相对路径非常有用,虽然在实际中用的并不多,因为Ant的文件和路径已经具有了自动展开的功能。

l         File resolveFile(String filename):这个函数根据文件名返回带有绝对路径的File对象。假如文件名是个相对值,则它会根据工程的基准目录进行解析。

2.3 Path

l         String toString()返回经过完全解析的、且平台相关的完整路径信息。

l         static String[]  translatePath(Project project , String path)这个工具函数根据某个路径分解得到路径元素数组,那个路径包含着由冒号或者分号分隔开来的路径元素。

l         int size():返回Path实例中路径元素的数量。

l         String[] list():返回Path实例中路径元素数组。

2.4 Fileset

2.5 DirectoryScanner

2.6 EnumeratedAttribute

2.7 FileUtils

3 任务获取数据的机制

在构建文件中,任务是由XML元素的形式来声明的,它包含了属性、子元素以及文本。在Ant中,任务可以通过多种形式的途径获取领域相关(domain-specific)的信息。

在构建文件执行过程中,Ant为用到的任务所对应的类建立实例,并将属性和子元素的消息传递给它。利用Java的内省(introspection)机制,Ant寻找特定命名的函数,并用构建文件的数据调用这些函数。在数据传送过程中,Ant任务和其它成分(例如datatypetarget以及project)都是平等的,都对应一个对象。

3.1 属性

XML属性其实就是一个名值对。假如你现在有一个仅有一个属性的任务:

       <sometask  value=”some value”/>

这个任务有个setValue的函数:

       private  String  value;

       public  void  setValue  (String  value) {

              phis.value = value;

}

这和JavaBean的命名风格很相似,每个特性都对应一个读写器(setter/getter)。属性的内省机制支持Java的基本类型和包装类型,而类型之间的转换出现错误的话,将抛出NumberFormatException异常,构建过程将停止。

通过实现一个以java.io.File参数的设值函数,Ant提供了对文件或者目录属性内置的支持,它可以将构建文件中的相对目录解析为绝对路径。

<mytask  destdir =”output”/>

对应的任务就实现了setDestDir函数:

private  File  destDir;

public  void  setDestDir(File  destDir) {

       This.destDir  =  destDir;

}

3.2 支持嵌套元素

当遇到嵌套元素时,Ant会在任务中寻找特定命名的函数,然后调用它。下面是三种特定的Ant调用特定命名函数的情况:

l         Ant可以利用默认构造函数创建对象,且无需前期配置:public void addElementName(Object obj)

l         Ant可以利用默认的构造函数创建对象,但需要前期配置:public void addConfigredElementName(ObjectTyep obj)

l         需要你的任务自行创建对象:public ObjectType createElementName()

建议对嵌套的元素使用addXXX(或者addConfiguredXXX)函数,而不是createXXX函数,因为前者允许类型的多态。

3.3 支持Datatypes

嵌套的datatype隐式地支持refid引用,所以无需在任务的代码中显性地增加这个支持。如果试图导入对定制datatype的引用,就必须用相同的类加载器(classloader)载入任务和datatype。当将JAR文件放入Antlib目录中时,上述操作就会自动进行。如果你在<taskdef><datatype>声明中指定了一个类加载器,那么就必须在所有的声明中,将loaderref属性设置为引用相同的类加载器。

4 Ant Task例子

在这里自定义的任务都从org.apache.tools.ant.Task扩展,因为这样可以访问Ant的内部APITask类提供了:

l         所属目标的入口

l         当前工程的入口

l         日志工具

不扩展AntTask类,通过自定义一些同名函数,依然可以访问工程实例和日志工具。这样的好处在于避免了你的泪依赖于Ant,同时又能保持自己的继承层次体系。一旦使用了Ant内部的API,就建立了与Ant的依赖关系。如果你为了保持继承层次体系,可以将其他的Java类包装到Task子类中去,Task子类就变成了一个包装类(wrapper),这样既可以修改被包装的代码,又可以保持任务与构建文件的访问借口不变。

4.1 添加属性

下面是一个从Task扩展的基本的Ant任务,同时还带有一个可选的属性:

package org.cactus.ant.task

import org.apache.tools.ant.Task;

 

public class MessageTask extends Task{

       private String message = “ ”;

       public void setMessage(String message){

              this.message = message;

}

public void execute(){

       log(message);

}

}

从而在构建文件中就可以这样使用了:

<target name=”messagetask” depends=”compile”>

       <taskdef name=”message” classname=”org.cactus.ant.task.MessageTask”

Classpath=”${build.dir}”>

              <property name = “the.message” value=”blue scooter”/>

              <message message=”${the.message}”/>

</target>

4.2 处理元素文本

addText函数将元素文本传递给它所属的对象,通常是任务自身,即将构建文件中的文本传递给自定义的类。在传递过程中对文本不做任何的变动,也不对特性引用进行展开。我们现在对上面的例子进行一些修改:

package org.cactus.ant.task

import org.apache.tools.ant.Task;

 

public class MessageTask2 extends Task{

       private String message = “ ”;

       public void addText(String message){

              this.message = message;

}

public void execute(){

       log(message);

}

}

而构建文件中的片断如下:

<property name=”another.message” value=”light up ahead”/>

<message2>${another.message}</message2>

输出结果是:

[message2] ${another.message}

如果你想解析特性的引用,只需要调用一个Project函数就行:

public void execute( ){

log(getProject( ).replaceProperties(message));

}

5 构建任务库

构建可重用任务库,从而使得在编写构建文件时,能更加方便地使用已有的任务。在库中包含一个特性文件,用它可以将构建文件中的任务名映射到实际实现的Java类名:

message=org.cactus.ant.task.MessageTask

message2=org.cactus.ant.task.MessageTask

然后再将这个库打成一个jar包,这样一个新的自定义的Ant任务就可以使用了。

 

【上篇】
【下篇】

抱歉!评论已关闭.