Ant 是一个 Apache 基金会下的跨平台的构件工具,现已经被广泛的应用在了各个开源的项目的构架。
Ant自身提供了一系列的Core Task,可以轻松的实现目录管理,编译,运行等功能。当然除了Core Task提供的功能之外,我们也有一些功能上的扩展的需求。很简单的方式是把自定义的功能封成jar包,调用Task-java来执行主类,这样做的问题是输入的属性将会以参数串的形式出现,很不直观。所以ant提供了另一种方式:自定义Task。自定义Task和Core-Task一样,有自己的Task名和属性。下面来讲一下如何自定义ant Task,以及自定义Task的的创建。
这部分在ant的手册里面写的很清楚,贴一段先
It is very easy to write your own task:
org.apache.tools.ant.Task
or another class that was designed to be extended. public void
method that takes a single argument. The name of the method must begin with set
, followed by the attribute name, with the first character of the name in uppercase, and the rest in lowercase*. That is, to support an attribute named file
you create a method setFile
. Depending on the type of the argument, Ant will perform some conversions for you, see below. parallel
), your class must implement the interface org.apache.tools.ant.TaskContainer
. If you do so, your task can not support any other nested elements. See below. public void addText(String)
method. Note that Ant does not expand properties on the text it passes to the task. public
method that takes no arguments and returns an Object
type. The name of the create method must begin with create
, followed by the element name. An add (or addConfigured) method must be a public void
method that takes a single argument of an Object
type with a no-argument constructor. The name of the add (addConfigured) method must begin with add
(addConfigured
), followed by the element name. For a more complete discussion see below. public void execute
method, with no arguments, that throws a BuildException
. This method implements the task itself. 简单的翻译一下,
首先要把%ANT_HOME%/lib下的ant.jar引入classpath,创建一个org.apache.tools.ant.Task 的子类。
如果要支持一个属性,只需要简单的实现一个public的函数,函数名为set+属性的小写。如果用户填写了该属性,ant会自动调用该函数。
如果要支持级联的属性,则应该实现org.apache.tools.ant.TaskContainer的接口。
重载父类的public void execute函数,并在里面实现主逻辑,如果出错,请抛出一个BuildException的异常,因为函数没返回值。
下面来两个例子:
package com.mydomain; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; public class MyVeryOwnTask extends Task { private String msg; // The method executing the task public void execute() throws BuildException { System.out.println(msg); } // The setter for the "message" attribute public void setMessage(String msg) { this.msg = msg; } }
It's really this simple ;-)
Adding your task to the system is rather simple too:
<taskdef>
element to your project. This actually adds your task to the system. <?xml version="1.0"?>
<project name="OwnTaskExample2" default="main" basedir=".">
<target name="build" >
<mkdir dir="build"/>
<javac srcdir="source" destdir="build"/>
</target>
<target name="declare" depends="build">
<taskdef name="mytask"
classname="com.mydomain.MyVeryOwnTask"
classpath="build"/>
</target>
<target name="main" depends="declare">
<mytask message="Hello World! MyVeryOwnTask works!"/>
</target>
</project>
嵌套的情况则需要实现一个节点类,并在父类上用Vector来替换String表示属性,这里面就不具体做介绍了。
2.如何调试自定义的Task
ant本身是个批处理,逻辑也是用java实现的,结合上面的了解,可以看出自定义的类Task是以refect的方式由java虚拟机加载执行的。即主类存在用户的工程里面。一种方式是将ant的相应jar引入当前工程的classpath,创建一个application的debug配置,将主类设置为ant的主类:org.apache.tools.ant.launch.Launcher。但存在的问题很多,首先ant执行的环境变量,当前目录等都和真正的运行环境有所区别。要配置很多的环境信息和参数,不利于多次调试。
我推荐的方式是利用java的远程调试来达到调试的目的。
2.1 创建远程调试server
Java远程调试
-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,address=3999,suspend=n
-XDebug 启用调试。
-Xnoagent 禁用默认sun.tools.debug调试器。
-Djava.compiler=NONE 禁止 JIT 编译器的加载。
-Xrunjdwp 加载JDWP的JPDA参考执行实例。
transport 用于在调试程序和 VM 使用的进程之间通讯。
dt_socket 套接字传输。
dt_shmem 共享内存传输,仅限于 Windows。
server=y/n VM 是否需要作为调试服务器执行。
address=3999 调试服务器的端口号,客户端用来连接服务器的端口号。
suspend=y/n 是否在调试客户端建立连接之后启动 VM 。
Java的远程调试JDPA是基于JDWP协议的一种交互式调试方式,最大的特点是VM的运行环境和调试环境相互独立。这样就可以很好的解决运行和调试的环境问题。
要实现远程调试,需要在server端的虚拟机参数中加入:
-Xdebug -Xrunjdwp:transport=dt_socket,address=5050,server=y,suspend=y
即:使用端口的方式进行JDWP通讯,端口为5050,采用挂起的方式,只有客户端连上才启动虚拟机。
对于ant来说,此参数无疑要加到启动ant主类的参数中。我们分析ant.bat看到:
"%_JAVACMD%" %ANT_OPTS% -classpath "%ANT_HOME%/lib/ant-launcher.jar" "-Dant.home=%ANT_HOME%" org.apache.tools.ant.launch.Launcher %ANT_ARGS% %ANT_CMD_LINE_ARGS%
而%ANN_OPTS%这个环境变量在批处理之前并没有得到设置,看来这就是ANT留给我们的操作参数变量,创建一个debug_ant.bat
set ANT_OPTS=
-Xdebug -Xrunjdwp:transport=dt_socket,address=5050,server=y,suspend=y
call ant %*
用bebug_ant.bat来替换ant.bat就可以在不影响任何其它环境变量的情况下,启动远程调试server。
2.2 创建远程服务Client
用eclipse打开你的自定义Task所在的工程,打开Debug configuration,新增Remote Java Application
选择connection Type: Standard(SocketAttach)
选择connection Properties:
Host: local host
Port: 5050
2.3 开始调试
在对应的位置用debug_ant来替换ant执行相关的xml脚本,此时虚拟机会挂起。
在eclipse的代码相应位置设置好断点,采用刚刚创建的configuration进行调试。
此时ant的虚拟机将开始执行,并会在断点相应的位置上做出响应。
OK,现在享受你自定义的task带来的方便吧。