作者:EricM.Burke,译者:st 点击: <script src="/publish/news/counter.php?o=display&Id=1380"></script> 3 <script src="/publish/news/counter.php?Id=1380"></script> 日期:2004-09-27 18:21:33 |
在ANT出现之前,编译和部署Java应用需要使用包括特定平台的脚本、Make文件、不同的IDE以及手工操作等组成的大杂烩。现在,几乎所有的开源Java项目都在使用Ant,许多公司的开发项目也在使用Ant。Ant的大量使用,也自然带来了对总结Ant最佳实践的迫切需求。 本文总结了我喜好的Ant最佳实践,很多是从亲身经历的项目错误,或从其他开发者的“恐怖”故事中得到的灵感的。比如,有人告诉我有个项目将XDoclet 生成的代码放入锁定文件的版本控制工具中。单开发者修改源代码时,他必须记住手工检出(Check out)并锁定所有将要重生成的文件。然后,手工运行代码生成器,当他能够让Ant编译代码时,这一方法还存在一些问题:
|
8. 定义恰当的任务参数关系
假设dist任务从属于jar任务,那么哪个任务从属于compile任务,哪个任务从属于prepare任务呢? Ant 构建文件最终定义了任务的从属关系图,它必须被仔细地定义和维护。 应该定期检查任务的从属关系以保证构建工作得到正确执行。大的构建文件随着时间推移趋向于增加更多的任务,所以到最后由于不必要的从属关系导致构建工作非常困难。比如,你可能发现在程序员只是需要编译一些没有使用 EJB 的GUI代码时,重新生成 EJB 代码。 以“优化”的名义忽略任务的从属关系是另一种常见的错误。这种错误迫使程序员为了得到恰当的结果必须记住并按照特定的顺序调用一串任务。更好的做法是:提供描述清晰的公共任务,这些任务包含正确的任务从属关系;另外提供一套“专家”任务让你能够手工执行个别的构建步骤,这些任务不提供完整的构建过程,但是让那些专家在快速而恼人的编码期间跳过某些步骤。
9.使用配置属性
任何需要配置或可能发生变化的信息都应作为 Ant 属性定义下来。对于在构建文件中多次出现的值也同样处理。属性既可以在构建文件头部定义,也可以为了更好的灵活性而在单独的属性文件中定义。以下是在构建文件中定义属性的样式:
<project name="sample" default="compile" basedir="."> <property name="dir.build" value="build"/> <property name="dir.src" value="src"/> <property name="jdom.home" value="http://www.kissjava.com/doc/javamore/ant/images/h00/h38/> <property name="jdom.jar" value="jdom.jar"/> <property name="jdom.jar.withpath" value="${jdom.home}/build/${jdom.jar}"/> etc... </project> |
或者你可以使用属性文件:
<project name="sample" default="compile" basedir="."> <property file="sample.properties"/> etc... </project> |
在属性文件 sample.properties中:
dir.build=build dir.src=src jdom.home=http://www.kissjava.com/doc/javamore/ant/images/h00/h38/jdom-b8 jdom.jar=jdom.jar jdom.jar.withpath=${jdom.home}/build/${jdom.jar} |
10. 保持构建过程独立 为了最大限度的扩展性,不要应用外部路径和库文件。最重要的是不要依赖于程序员的CLASSPATH设置。取而代之的是,在构建文件中使用相对路径并定义自己的路径。如果你引用了绝对路径如C:/java/tools,其他开发者未必使用与你相同的目录结构,所以就无法使用你的构建文件 如果你部署开发源码项目,应该提供包括所有需要的JAR文件的发行版本,当然是在遵守许可协议的基础上。对于内部项目,相关的JAR文件都应在版本控制系统的管理中,并捡出到大家都知道的位置。 当你不得不应用外部路径时,应将路径定义为属性。使程序员能够涌适合他们自己的机器的参数重载这些属性。你也可以使用以下语法引用环境变量:
<property environment="env"/> <property name="dir.jboss" value="${env.JBOSS_HOME}"/> |
11. 使用版本控制系统 构建文件是一个重要的文件,应该象代码一样进行版本控制。当你标记你的代码时,也应用同样的标签标记构建文件。这样当你需要回溯构建旧版本的软件时,能够使用相对应的旧版本构建文件。 除构建文件之外,你还应在版本控制中维护第三方JAR文件。同样,这使你能够重新构建旧版本的软件。这也能够更容易保证所有开发者拥有一致的JAR文件,因为他们都是同构建文件一起从版本控制系统中捡出的。 通常应避免在版本控制系统中存放构建输出品。倘若你的源代码很好地得到了版本控制,那么通过构建过程你能够重新生成任何版本的产品。
12. 把Ant作为“最小公分母”
假设你的开发团队使用IDE,为什么要为程序员通过点击图标就能够构建整个应用而烦恼呢? IDE的问题在团队中是一个关于一致性和重现性的问题。几乎所有的IDE设计初衷都是为了提高程序员的个人生产率,而不是开发团队的持续构建。典型的IDE要求每个程序员定义自己的项目文件。程序员可能拥有不同的目录结构,可能使用不同版本的库文件,还可能工作在不同的平台上。这将导致出现这种情况:在A那里运行良好的代码,到B那里就无法运行。 不管你的开发团队使用何种IDE,一定要建立所有程序员都能够使用的 Ant 构建文件。要建立一个程序员在将新代码提交版本控制系统前必须执行 Ant 构建文件的规则。这将确保代码是经过同一个 Ant 构建文件构建的。当出现问题时,要使用项目标准的 Ant 构建文件,而不是通过某个IDE来执行一个干净的构建。
程序员可以自由选择任何他们习惯使用的IDE。但是 Ant 应作为公共基线以保证永远是可构建的。
13. 使用 zipfileset属性
人们经常使用 Ant 产生WAR、JAR、ZIP和 EAR文件。这些文件通常都要求有一个特定的内部目录结构,但其往往与你的源代码和编译环境的目录结构不匹配。 一个最常用的方法是写一个 Ant 任务按照期望的目录结构把一大堆文件拷贝到临时目录中,然后生成压缩文件。这不是最有效的方法。使用zipfileset属性是更好的解决方案。它让你从任何位置选择文件,然后把它们按照不同目录结构放进压缩文件中。以下是一个例子:
<ear earfile="${dir.dist.server}/payroll.ear" appxml="${dir.resources}/application.xml"> <fileset dir="${dir.build}" includes="commonServer.jar"/> <fileset dir="${dir.build}"> <include name="payroll-ejb.jar"/> </fileset> <zipfileset dir="${dir.build}" prefix="lib"> <include name="hr.jar"/> <include name="billing.jar"/> </zipfileset> <fileset dir="."> <include name="lib/jdom.jar"/> <include name="lib/log4j.jar"/> <include name="lib/ojdbc14.jar"/> </fileset> <zipfileset dir="${dir.generated.src}" prefix="META-INF"> <include name="jboss-app.xml"/> </zipfileset> </ear> |
14. 运行 Clean 构建任务的测试
假设你的构建文件中有clean和compile的任务,执行以下的测试。第一步,执行ant clean;第二步,执行ant compile;第三步,再执行ant compile。第三步应该不作任何事情。如果文件再次被编译,说明你的构建文件有问题。 构建文件应该只在与输出文件相关联的输入文件发生变化时,才应该执行任务。一个构建文件在不必执行诸如编译、拷贝或其他工作任务的时候执行这些等任务是低效的。当项目规模增长时,即使是小的低效工作也会成为大的问题。
15. Avoid Platform-Specific Ant Wrappers
不管什么原因,有人喜欢用简单的、名称叫做compile之类的批文件或脚本装载他们的产品。当你去看脚本的内容,你会发现以下内容:
ant compile
其实开发人员熟悉 Ant ,并且完全能够自己键入ant compile。请不要仅仅为了调用 Ant 而使用特定平台的脚本。这只会使其他人在首次使用你的脚本时,增加学习和理解的烦扰。除此之外,你不可能提供适用于每个操作系统的脚本,这是真正烦扰其他用户的地方。
总结 太多的公司依靠手工方法和程序来编译代码和生成软件发布版本。那些不使用 Ant 或类似工具定义构建过程的开发团队,花费了令人惊异的时间来捕捉代码编译过程中出现的问题,这些在某些开发者那里编译成功的代码,到另一些开发者那里却失败了。
生成并维护构建脚本不是一项迷人的工作,但却是一项必需的工作。一个好的 Ant 构建文件将使你集中到更喜欢的工作——写代码中!
参考
· Ant
· Ant Graph: Ant 依赖性的可视化工具
· Ant : The Definitive Guide, O'Reilly
· Java Extreme Programming Cookbook, O'Reilly