作为现在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.out和System.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( )方法。

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函数。其中有五个日志级别(按优先级排列):

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任务和其它成分(例如datatype、target以及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文件放入Ant的lib目录中时,上述操作就会自动进行。如果你在<taskdef>和<datatype>声明中指定了一个类加载器,那么就必须在所有的声明中,将loaderref属性设置为引用相同的类加载器。

4 Ant Task例子

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

l         所属目标的入口

l         当前工程的入口

l         日志工具

不扩展Ant的Task类,通过自定义一些同名函数,依然可以访问工程实例和日志工具。这样的好处在于避免了你的泪依赖于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任务就可以使用了。

ant学习笔记—自定义Ant任务相关推荐

  1. iOS学习笔记-自定义过渡动画

    代码地址如下: http://www.demodashi.com/demo/11678.html 这篇笔记翻译自raywenderlick网站的过渡动画的一篇文章,原文用的swift,由于考虑到swi ...

  2. MySQL学习笔记—自定义函数

    MySQL学习笔记-自定义函数 注释语法: MySQL服务器支持3种注释风格: 从'#'字符从行尾. 从'– '序列到行尾.请注意'– '(双破折号)注释风格要求第2个破折号后面至少跟一个空格符(例如 ...

  3. Ant学习笔记(Ant入门)

    Apache Ant是一个基于java的生成工具,another neat tool. 首先需要配置ANT..先去http://ant.apache.org下载其jar包.我下载的是Apache An ...

  4. ant学习笔记之(ant执行命令的详细参数和Ant自带的系统属性)

    2019独角兽企业重金招聘Python工程师标准>>> 一:ant执行命令的详细参数 -buildfile<file>,-file<file>,-f<f ...

  5. antd vue表单上传文件_AntDesign vue学习笔记-自定义文件上传

    上传文件时实际可能需要传输一个token. 方法一: 1.查看vue antdesign文档 https://vue.ant.design/components/upload-cn/ 2.使用cust ...

  6. Vaadin学习笔记——自定义vaadin组件的样式

    在开始阅读本文之前,你需要先了解以下内容: CSS相关知识(如选择器.如何编写CSS rule等) HTML相关知识(元素.class属性.DOM层级结构等) Vaadin相关知识(如怎样创建.运行V ...

  7. Android开发学习笔记-自定义对话框

    系统默认的对话框只能显示简单的标题内容以及按钮,而如果想要多现实其他内容则就需要自定义对话框,下面是自定义对话框的方法. 1.先定义对话框的模版 <?xml version="1.0& ...

  8. Android开发学习笔记-自定义组合控件

    为了能让代码能够更多的复用,故使用组合控件.下面是我正在写的项目中用到的方法. 1.先写要组合的一些需要的控件,将其封装到一个布局xml布局文件中. <?xml version="1. ...

  9. mysql vtype_ExtJs6学习笔记 -- 自定义 vtype

    1.Vtype 即 validate type ,验证类型.在Ext中有以下几种自带的Vtype: alphanum  //数字,字母,_ url   //url 2.自定义Vtype Ext.onR ...

最新文章

  1. js数组的排序 sort详解
  2. 发改委最新《产业结构调整目录》公布!数据中心列入鼓励产业条目
  3. TCP/IP协议(二)tcp/ip基础知识
  4. 调用startActivityForResult后,onActivityResult无响应的题目
  5. eclipse中去掉警告提示
  6. No fallback instance of type class found for feign client user-service(转)
  7. js遍历数组foreach_JavaScript forEach –如何在JS中遍历数组
  8. stl 基于哈希的map c++_关于哈希表,你该了解这些!
  9. n 个骰子点数和及各自出现的概率
  10. 海美迪盒子android升级包,海美迪H6官方固件ROM升级包下载_刷机教程
  11. 机器学习笔记:训练集、验证集与测试集
  12. 单AP对多终端无线上行带宽下降问题
  13. API开发手册在线中文版
  14. 深度学习--python 读取并显示图片的方法
  15. webpack 打包异常 unhandledRejection 错误详情查看
  16. Ubuntu 16.04/18.04/20.04/deepin v20安装insight的方法
  17. UVa-1583 生成元
  18. python | 绘制中国地形图(带中国边界省界)
  19. 606.根据二叉树创建字符串
  20. java程序员培训学院,年薪60W必备

热门文章

  1. 【云贝学院】腾讯云TDSQL-数据库字符集
  2. 敏感词过滤案例(Filter过滤器)
  3. 《活着中文版自序》感悟
  4. Python之ruamel.yaml模块详解(三)| ruamel.yaml与pyyaml的区别
  5. 关于录取志愿者培训人员名单的通知
  6. IP查询和IPv6查询接口
  7. 已解决requests.exceptions.ConnectTimeout: HTTPConnectionPool(host=‘123.96.1.95‘, port=30090): Max retri
  8. x86嵌入式主板定制版型选购标准
  9. 文内码转换巨匠增强版 官方版
  10. sass + compass