使用自定义任务来扩展Ant.docx
- 文档编号:3532323
- 上传时间:2022-11-23
- 格式:DOCX
- 页数:14
- 大小:28.21KB
使用自定义任务来扩展Ant.docx
《使用自定义任务来扩展Ant.docx》由会员分享,可在线阅读,更多相关《使用自定义任务来扩展Ant.docx(14页珍藏版)》请在冰豆网上搜索。
使用自定义任务来扩展Ant
使用自定义任务来扩展Ant
简介
正如我们从前述几节中所看到的,Ant非常强大,具有涵盖广泛功能集的许多核心任务。
它还有许多这里没有介绍的附加任务,再加上提供广泛附加功能的许多可选任务,以及作为Ant-Contrib项目的一部分来提供的其他任务;最后,ApacheAnt主页上还列出了外部可用的更多任务。
面对Ant提供的所有这些任务,您似乎再也不需要其他任务了,但是Ant的真正力量在于它的易于扩展性。
事实上,恰恰正是这种可扩展性促使人们开发了如此多的附加任务。
可能会存在这样的场合,在那样的场合下创建自定义的任务更为合适。
例如,假设您创建了一个命令行工具来执行某个特定操作;这个工具可能是将对Ant可用的任务的恰当候选者(当该工具是用Java语言编写的时更是这样,虽然该工具不一定是用Java语言编写的。
)与其让Ant使用exec任务外部地调用该工具(这样将引入依赖关系,并使得生成文件在跨越不同平台时更难于使用),您可以将它直接合并到生成文件中。
还可以使得Ant的常规文件集和通配符匹配功能对自定义的任务可用。
在本节中,我们将考察一个简单自定义任务的构造过程。
这个任务将对文件中的行执行排序操作,并将排序后的行集写到一个新文件中。
创建自定义的任务
为实现一个简单的自定义任务,我们所需做的就是扩展org.apache.tools.ant.Task类,并重写execute()方法。
因此,作为这个文件排序自定义任务的框架,我们将编写如下代码:
importorg.apache.tools.ant.BuildException;
importorg.apache.tools.ant.Task;
publicclassFileSorterextendsTask{
//Themethodexecutingthetask
publicvoidexecute()throwsBuildException{}
}
注意我们声明execute()方法抛出一个BuildException异常。
如果这个任务出了任何错误,我们将抛出这个异常以便向Ant指出故障。
大多数任务,不管是核心任务还是自定义任务,都利用属性来控制它们的行为。
对于这个简单任务,我们需要一个属性来指定要排序的文件,需要另一个属性来指定排序内容的输出。
我们把这两个属性分别叫做file和tofile。
Ant使得支持自定义任务中的属性非常容易。
为此,我们只需实现一个具有特别格式化的名称的方法,Ant能够使用生成文件中指定的对应属性的值来调用这个方法。
这个方法的名称需要是set加上属性的名称,因此在这个例子中,我们需要名为setFile()和setTofile()的方法。
当Ant遇到生成文件中的一个属性设置时,它会寻找相关任务中具有适当名称的方法(称为setter方法)。
生成文件中的属性是作为字符串来指定的,因此我们的setter方法的参数可以是一个字符串。
在这样的情况下,Ant将在展开值所引用的任何属性之后,使用该属性的字符串值来调用我们的方法。
但有时我们想把属性的值看作是一种不同的类型。
这里的示例任务就是这种情况,其中的属性值引用文件系统上的文件,而不只是引用任意的字符串。
可以通过将方法参数声明为java.io.File类型来容易地做到这点。
Ant将接受属性的字符串值,并把它解释为一个文件,然后传递给我们的方法。
如果文件是使用相对路径名称来指定的,则会被转换为相对于项目基目录的绝对路径。
Ant能够对其他类型执行类似的转换,比如boolean和int类型。
如果您提供具有相同名称但是具有不同参数的两个方法,Ant将使用更明确的那一个方法,因此文件类型将优先于字符串类型。
这个自定义任务需要的两个setter方法类似如下:
//Thesetterforthe"file"attribute
publicvoidsetFile(Filefile){}
//Thesetterforthe"tofile"attribute
publicvoidsetTofile(Filetofile){}
实现自定义的任务
使用前一小节开发的框架,现在我们能够完成这个简单的文件排序任务的实现:
importjava.io.*;
importjava.util.*;
importorg.apache.tools.ant.BuildException;
importorg.apache.tools.ant.Task;
/**
*Asimpleexampletasktosortafile
*/
publicclassFileSorterextendsTask{
privateFilefile,tofile;
//Themethodexecutingthetask
publicvoidexecute()throwsBuildException{
System.out.println("Sortingfile="+file);
try{
BufferedReaderfrom=
newBufferedReader(newFileReader(file));
BufferedWriterto=
newBufferedWriter(newFileWriter(tofile));
ListallLines=newArrayList();
//readintheinputfile
Stringline=from.readLine();
while(line!
=null){
allLines.add(line);
line=from.readLine();
}
from.close();
//sortthelist
Collections.sort(allLines);
//writeoutthesortedlist
for(ListIteratori=allLines.listIterator();i.hasNext();){
Strings=(String)i.next();
to.write(s);to.newLine();
}
to.close();
}catch(FileNotFoundExceptione){
thrownewBuildException(e);
}catch(IOExceptione){
thrownewBuildException(e);
}
}
//Thesetterforthe"file"attribute
publicvoidsetFile(Filefile){
this.file=file;
}
//Thesetterforthe"tofile"attribute
publicvoidsetTofile(Filetofile){
this.tofile=tofile;
}
}
两个setter方法简单地对属性的值排序,以便这些值能够在execute()方法中使用。
这里,输入文件被逐行地读入一个列表中,然后被排序并逐行地输出到输出文件。
注意,为简单起见,我们很少执行错误检查——例如,我们甚至没有检查生成文件是否设置了必需的属性。
不过我们的确至少捕捉了所执行的操作抛出的I/O异常,并将这些异常作为BuildExceptions重新抛出。
现在可以使用javac编译器或从某个IDE内编译这个自定义的任务。
为了解决所使用的Ant类的引用问题,您需要把ant.jar文件的位置添加到classpath中。
这个文件应该在Ant安装路径下的lib目录。
使用自定义的任务
现在我们已经开发和编译了这个自定义的任务,下面可以从生成文件中利用它了。
在能够调用自定义的任务之前,我们需要给它指定一个名称来定义它,并告诉Ant关于实现这个任务的类文件的信息,以及定位该类文件所必需的任何classpath设置。
这是使用taskdef任务来完成的,如下所示:
classname="FileSorter" classpath="."/> 大功告成! 现在可以像使用Ant的核心任务一样使用这个自定义的任务了。 下面是一个完整的生成文件,它显示了这个自定义任务的定义和用法: xmlversion="1.0"? > classname="FileSorter classpath="."/> 现在在当前工作目录中创建一个input.txt文件来测试这个自定义的任务。 例如: Hellothere Thisisaline Andhereisanotherone 下面是运行上面的生成文件之后产生的控制台输出: Buildfile: build.xml main: [filesorter]Sortingfile=E: \tutorial\custom\input.txt BUILDSUCCESSFUL Totaltime: 0seconds 注意input.txt的相对路径名称被转换成了当前目录中的一个绝对路径名称。 这是因为我们将setter方法的参数指定为java.io.File类型而不是java.lang.String类型。 现在看一下这个任务实际是否能工作。 这时应该已经在同一目录中创建了名为output.txt的文件,它包含以下内容: Andhereisanotherone Hellothere Thisisaline 您可以尝试指定一个不存在的输入文件,以确定该任务是如何向Ant报告“filenotfound”异常的。 ant自动jar包分析 以前都是用maven2做项目管理,但最近又用回了ant脚本执行打包,发现每次改变工程得jar依赖后打war包很麻烦,还得手工改变build.xml中的引用,所以为了偷懒就的相隔一劳永逸的办法,于是产生了如下偷懒的代码(可能技术进步都是因为我们想从无意义的手工劳动中解脱出来) 1.扩展的ant类,分析classpath文件,替换变量M2_REPO以获得依赖jar的全路径,并执行copy java代码 1.import java.io.FileInputStream; 2.import java.io.FileNotFoundException; 3.import java.io.IOException; 4.import java.util.ArrayList; 5.import java.util.Iterator; 6.import java.util.List; 7. 8.import org.apache.tools.ant.BuildException; 9.import org.apache.tools.ant.Project; 10.import org.apache.tools.ant.Task; 11.import org.apache.tools.ant.util.FileUtils; 12.import org.dom4j.Document; 13.import org.dom4j.Element; 14.import org.dom4j.io.SAXReader; 15. 16. 17./** 18. * 类说明: 分析.classpath文件的jar引用,并copy到war 19. * 创建时间: 2007-10-31 下午02: 23: 42 20. * @authorSeraph 21. * @email: seraph115@ 22. */ 23.public class AntPathTask extends Task { 24. 25. private static final String M2_REPO = "M2_REPO"; 26. 27. private static final String ECLIPSE_DOM = "/classpath/classpathentry"; 28. 29. private String libdir; 30. 31. private String repository; 32. 33. private String classpath; 34. 35. public String getLibdir() { 36. return libdir; 37. } 38. 39. public void setLibdir(String libdir) { 40. this.libdir = libdir; 41. } 42. 43. public String getRepository() { 44. return repository; 45. } 46. 47. public void setRepository(String repository) { 48. this.repository = repository; 49. } 50. 51. public String getClasspath() { 52. return classpath; 53. } 54. 55. public void setClasspath(String classpath) { 56. this.classpath = classpath; 57. } 58. 59. public Project getProject() { 60. return super.getProject(); 61. } 62. 63. public void execute() throws BuildException { 64. 65. List list = getPathFromEclipseFile(); 66. copyJar(list); 67. showPath(list); 68. } 69. 70. public List getPathFromEclipseFile() { 71. 72. SAXReader saxReader = new SAXReader(); 73. Document document = null; 74. try { 75. document = saxReader.read(new FileInputStream(classpath)); 76. } catch (Exception e) { 77. e.printStackTrace(); 78. } 79. 80. List list = document.selectNodes(ECLIPSE_DOM); 81. List pathList = new ArrayList(); 82. 83. int i = 0; 84. for (Iterator iterator = list.iterator(); iterator.hasNext();) { 85. Element element= (Element) iterator.next(); 86. 87. String kind = element.attributeValue("kind"); 88. if("var".equals(kind)){ 89. String path = element.attributeValue("path"); 90. path = path.replaceAll(M2_REPO, repository); 91. pathList.add(path); 92. i++; 93. } 94. } 95. return pathList; 96. } 97. 98. public void copyJar(List list) { 99. 100. FileUtils fileUtils = FileUtils.newFileUtils(); 101. for (Iterator iterator = list.iterator(); iterator.hasNext();) { 102. String fileName = (String) iterator.next(); 103. String[] strs = null; 104. try { 105. strs = fileName.split("/"); 106. String destFile = libdir + "/" + strs[strs.length - 1]; 107. fileUtils.copyFile(fileName, destFile, null, true); 108. } catch (FileNotFoundException e1) { 109. log("指定的变量[M2_REPO]路径下找不到所需Jar,请配置正确路径。 所需文件: " 110. + strs[strs.length - 1], Project.MSG_ERR); 111. } catch (IOException e2) { 112. e2.printStackTrace(); 113. } 114. } 115. } 116. 117. public void showPath(List list) { 118. 119. log("Find .classpath file path of eclipse is: \"" + classpath + "\""); 120. log("CRMS Project include jar files: "); 121. 122. for (Iterator iterator = list.iterator(); iterator.hasNext();) { 123. String path = (String) iterator.next(); 124. log(path); 125. } 126. log("Total of jar files: " + list.size()); 127. } 128.} 2.ant的build.xml文件,使用扩展的ant任务taskdef,其中M2_REPO是eclipse的变量,而工程所引用的依赖都是通过此变量添加到工程中的 Xml代码 1. xml version="1.0" encoding="UTF-8"? > 2. 3. 4. /repository" /> 5. 6. 7.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 使用 自定义 任务 扩展 Ant
![提示](https://static.bdocx.com/images/bang_tan.gif)